当前位置: 首页 > 知识库问答 >
问题:

使用URLPrefix的Google Cloud CDN signedurl

赵炯
2023-03-14

我不能得到一个签名的URL与谷歌Cload CDN的URLPrefix一起工作。

https://example.com/foo.mp4?expires=[expersion]&keyname=[KEY_NAME]&SIGNATURE=[SIGNATURE]

export function signCdnUrl2(fileName: string, opts: SignedUrlOptions, urlPrefix?: string) {
    const expireVal = '' + new Date().getTime() + opts.expires;
    const urlToSign = `${opts.baseUrl}/${fileName}?Expires=${expireVal}&KeyName=${opts.keyName}`;

    // Compute signature
    const keyBuffer = Buffer.from(opts.keyBase64, 'base64');
    let signature = createHmac('sha1', keyBuffer).update(urlToSign).digest('base64');
    signature = Base64urlUtil.escape(signature);

    // Add signature to urlToSign and return signedUrl
    return urlToSign + `&Signature=${signature}`;
}
export function signCdnUrl3(fileName: string, opts: SignedUrlOptions, urlPrefix?: string) {

    const expireVal = '' + new Date().getTime() + opts.expires;

    const urlPrefixCombined = `${opts.baseUrl}${urlPrefix}`;
    // UrlPrefix param if provided otherwise empty string
    const urlPrefixEncoded = urlPrefix ? Base64urlUtil.encode(urlPrefixCombined) : '';

    // Param string to be signed with key
    const paramsToSign = `URLPrefix=${urlPrefixEncoded}&Expires=${expireVal}&KeyName=${opts.keyName}`;

    // Compute signature
    const keyBuffer = Buffer.from(opts.keyBase64, 'base64');
    let signature = createHmac('sha1', keyBuffer).update(paramsToSign).digest('base64');
    signature = Base64urlUtil.escape(signature);

    // Add signature to url
    return `${opts.baseUrl}/${fileName}?${paramsToSign}&Signature=${signature}`;
}

export class Base64urlUtil {

    public static encode(str: string, encoding: any = 'utf8'): string {
        const buffer: Buffer = Buffer.from(str, encoding);
        const encodedStr: string = buffer.toString('base64');
        const final: string = Base64urlUtil.escape(encodedStr);
        return final;
    }

    public static decode(str: string, encoding?: string): string {
        return Buffer.from(Base64urlUtil.unescape(str), 'base64').toString(encoding || 'utf8');
    }

    public static escape(str: string): string {
        return str.replace(/\+/g, '-')
            .replace(/\//g, '_')
            .replace(/=/g, '');
    }

    public static unescape(str: string): string {
        return (str + '==='.slice((str.length + 3) % 4))
            .replace(/-/g, '+')
            .replace(/_/g, '/');
    }
}
let signedParams = signURLPrefix(
  "https://<my-server>/sample/360p/",
  1588291200,
  "<my-key>",
  "<valid-key>"
)

URLPrefix=AHR0CHM6LY9ZCHLUYWWUCMNMC29MDHDHCMUUAW8VC2FTCGXLLZM2MHAV&Expires=1588291200&KeyName=My-Key-Name&Signature=WRBolot+M31ZNQZEI2CSQQ0XAGY=

然后,当我追加这些查询参数以调用位于以下地址的云cdnendpoint时:

https://my-server/sample/360p/video.mp4?URLPrefix=AHR0CHM6LY9ZCHLUYWWUCMNMC29MDHDCMUUAW8VC2FTCGXLLZM2MHAV&Expires=1588291200&KeyName=MY-Key-Name&Signature=WRBolot+M31ZNQZEI2CSQQ0XAGY=

我在cdn日志中得到相同的403响应和匹配的无效签名

尝试使用两个不同的签名密钥,这两个密钥对签名没有url前缀的单个特定url很有效。

共有1个答案

蒋栋
2023-03-14

不完全清楚哪里出了问题--我怀疑您可能对签名进行了双base64编码,但是base64urlutil没有包含在您提供的代码段中。

下面是一个工作版本,它生成与Go示例代码测试相同的签名:

const crypto = require("crypto")

export function signURLPrefix(
  urlPrefix: string,
  expires: number,
  keyName: string,
  key: string
) {
  const expireVal = expires
  const urlPrefixEncoded = Buffer.from(urlPrefix)
     .toString("base64")
     .replace(/_/g, '/')
     .replace(/-/g, '+')

  // Param string to be signed with key
  const paramsToSign = `URLPrefix=${urlPrefixEncoded}&Expires=${expireVal}&KeyName=${keyName}`

  // Compute signature
  const keyBytes = Buffer.from(key, "base64")
  // Expected key: []byte{0x9d, 0x9b, 0x51, 0xa2, 0x17, 0x4d, 0x17, 0xd9,
  // 0xb7, 0x70, 0xa3, 0x36, 0xe0, 0x87, 0x0a, 0xe3}
  let signature = crypto
    .createHmac("sha1", keyBytes)
    .update(paramsToSign)
    .digest("base64")
    .replace(/_/g, '/')
    .replace(/-/g, '+')

  return `${paramsToSign}&Signature=${signature}`
}

let signedParams = signURLPrefix(
  "https://media.example.com/segments/",
  1558131350,
  "my-key",
  "nZtRohdNF9m3cKM24IcK4w=="
)

let expected =
  "URLPrefix=aHR0cHM6Ly9tZWRpYS5leGFtcGxlLmNvbS9zZWdtZW50cy8=&Expires=1558131350&KeyName=my-key&Signature=HWE5tBTZgnYVoZzVLG7BtRnOsgk="

if (signedParams === expected) {
  console.log("✔️ Signature matches")
} else {
  console.error(
    `❌ Does not match: \n\tgot ${signedParams},\n\twant ${expected}`
  )
}

产出:

➜  ts-node signed_prefix.ts
✔️ Signature matches
 类似资料:
  • 我在Scala2.11.1和Hzaelcast 3.5中使用kryo进行序列化。我试图将数据放在hazelcast映射中,但我得到了KryoException 下面是我的用户类序列化程序 现在,当我将用户类对象从Hcast客户端放入相应的映射中时,如下所示 它给了我这些例外: 以下是中的 请帮帮我!!

  • 本文向大家介绍webpack proxy 使用(代理的使用),包括了webpack proxy 使用(代理的使用)的使用技巧和注意事项,需要的朋友参考一下 为什么要写篇文章 这两天的开发中遇到一些需要代理才能解决的问题, 在这里记录一下, 方便以后的查阅. 为什么要用代理 跨域 在开发过程中, 我们的开发环境一般都是http:// localhost, 但是如果需要请求的数据不在本地, 那么我们就

  • 如何使用Spring RestTemplate发送GET请求?其他问题都用了POST,但我需要用get。当我运行这个程序时,程序继续工作,但似乎网络堵塞了,因为它在一个AsyncTask中,当我单击这个按钮后试图运行另一个AsyncTask时,它们将无法工作。 我试着做

  • 问题内容: 最近,我尝试了解 java.math.MathContext 的用法,但未能正确理解。它用于四舍五入。如果是,为什么不四舍五入十进制数字,甚至尾数部分。 从API文档中,我知道它遵循,和规范中指定的标准,但是我没有让他们在线阅读。 如果您对此有任何想法,请告诉我。 问题答案: @贾坦 谢谢您的回答。这说得通。您能否在BigDecimal#round方法的上下文中向我解释MathCont

  • 主要内容:下载 Nexus 3,启动 nexus 服务,访问 nexus 3.x目前 Nexus 分为 Nexus 2 和 Nexus 3 两个大版本,它们是并行的关系。与 Nexus 2 相比,Nexus 3 具有很多优势,例如支持更多的仓库格式、优化了用户的使用界面以及更加强大的搜索功能等等。 目前使用最多的,运行最稳定是 Nexus 2,但随着 Nexus 3 对 Maven 的支持越来越稳定,很多公司和组织都陆续开始使用 Nexus 3。 本节我们将介绍 Nexus

  • 使用StaggedGridLayoutManager/GridLayoutManager如何使网格项在垂直方向上具有两个跨距,在水平方向上具有两个跨距?