You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Cloud CDN签名URL权限问题求助:无法访问私有存储桶文件

Cloud CDN签名URL权限错误排查与解决

问题场景

我通过Cloud CDN为应用私有分发存储桶文件,流程是应用调用云函数生成签名URL,返回给前端访问。负载均衡器已关联后端私有存储桶,且已为CDN服务账号授予存储桶的查看权限。

生成签名URL的代码如下:

const url = new URL(`https://cdn.mydomain.com/${filePathAndName}`);
const expires = Math.floor(Date.now() / 1000) + 60 * 60; //expires in 60 seconds

const urlToSign = `${url.pathname}?Expires=${expires}&KeyName=key1`;
const signature = crypto
  .createHmac("sha1", Buffer.from("generatedKey", "base64"))
  .update(urlToSign)
  .digest("base64")
  .replace(/\+/g, "-")
  .replace(/\//g, "_")
  .replace(/=+$/, "");

url.searchParams.append("Expires", expires.toString());
url.searchParams.append("KeyName", "key1");
url.searchParams.append("Signature", signature);

response.json({ url: url.toString()});

访问生成的链接时,收到错误:

Your client does not have permission to get URL /pathToFile/sample.mp3 from this server.

明明签名URL在有效期内,且CDN账号有存储桶权限,为何仍出现权限错误?


排查与解决步骤

1. 修复签名字符串的转义错误

你代码中构造urlToSign时使用了&(HTML转义的&符号),这是核心错误。Cloud CDN签名计算要求使用原始的URL查询字符串分隔符&,而非HTML转义后的字符。转义后的符号会导致签名计算的内容与CDN验证时的内容不匹配,直接触发权限拒绝。

修正后的urlToSign构造:

const urlToSign = `${url.pathname}?Expires=${expires}&KeyName=key1`;

2. 验证密钥解码逻辑

确认generatedKey是Cloud CDN控制台生成的base64格式签名密钥:

  • 如果密钥是控制台生成的,Buffer.from("generatedKey", "base64")是正确的解码方式;
  • 如果密钥是你自定义的明文密钥,需去掉base64参数,直接使用Buffer.from("generatedKey")。

3. 核对CDN签名配置

  • 确认CDN签名策略中配置的密钥名称key1存在且与代码一致;
  • 确认签名算法为SHA1,与代码中createHmac("sha1")匹配;
  • 检查CDN的签名验证参数名称(Expires、KeyName、Signature)是否与代码完全一致,避免自定义参数名导致验证失败。

4. 确认存储桶权限配置

  • 确保授予权限的账号是CDN服务账号(格式:service-<project-number>@cloud-cdn.iam.gserviceaccount.com);
  • 确认权限为storage.objects.get(对象读取权限),而非仅存储桶级别的storage.buckets.get;
  • 检查存储桶对象的ACL,避免对象单独设置的私有权限覆盖了CDN服务账号的访问权限。

修正后的完整代码

const url = new URL(`https://cdn.mydomain.com/${filePathAndName}`);
const expires = Math.floor(Date.now() / 1000) + 3600; // 修正注释:实际为1小时有效期,与代码逻辑一致

// 修复转义符问题
const urlToSign = `${url.pathname}?Expires=${expires}&KeyName=key1`;
const signature = crypto
  .createHmac("sha1", Buffer.from("generatedKey", "base64"))
  .update(urlToSign)
  .digest("base64")
  .replace(/\+/g, "-")
  .replace(/\//g, "_")
  .replace(/=+$/, "");

url.searchParams.append("Expires", expires.toString());
url.searchParams.append("KeyName", "key1");
url.searchParams.append("Signature", signature);

response.json({ url: url.toString()});

内容的提问来源于stack exchange,提问作者Victor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.15 10:13:19