我无法获得与 Google Cload CDN 的 URLPrefix 一起使用的签名 URL。
我已经设置了一个存储桶,它是我的 Cloud CDN 实例的后端存储桶。我已成功设置 URL 签名密钥并为特定路径生成了有效的签名 URL,所有这些都使用https://cloud.google.com/cdn/docs/using-signed-urls?hl=en_US中的说明
使用下面的 signCdnUrl2 函数,我可以为特定资源生成有效的签名 url,例如
https://example.com/foo.mp4?Expires=[EXPIRATION]&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}`;
}
我想避免“需要为每个不同的 URL 创建一个新签名”,所以我按照https://cloud.google.com/cdn/docs/using-signed-urls?hl=en_US#url-上的说明进行操作前缀以添加 URL 前缀选项。
我无法成功生成带有前缀的有效签名 url。我目前的尝试如下
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}`;
}
如果我尝试访问给定前缀下的任何资源(在存储桶的根目录下),我会从云 cdn 收到 403 响应
来自负载均衡器的日志条目显示它正在将其检测为无效签名
说明中有什么我解释错了,还是我在执行过程中遗漏了一些东西?任何指导将不胜感激。
添加了 Base64Util 代码以确保完整性
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, '/');
}
}
更新
使用@elithrar https://stackoverflow.com/a/61315372/4330441提供的实现,我将signedParams 中的样本值换成了我自己的实时值。
let signedParams = signURLPrefix(
"https://<my-server>/sample/360p/",
1588291200,
"<my-key>",
"<valid-key>"
)
结果是这样的:
URLPrefix=aHR0cHM6Ly9zcHluYWwucmNmc29mdHdhcmUuaW8vc2FtcGxlLzM2MHAv&Expires=1588291200&KeyName=my-key-name&Signature=wrbOloT+m31ZnQZei2Csqq0XaGY=
然后,当我附加这些查询参数以在此地址调用云 CDN 端点时:
我在 cdn 日志中得到相同的 403 响应和匹配的无效签名
尝试使用两个不同的签名密钥,它们可以很好地签名没有 url 前缀的单个特定 url。