Azure SAS令牌生成始终报Signature did not match错误的问题求助
我完全理解你现在的头疼——自己写Java代码生成的Azure SAS令牌总是返回403错误,提示「Signature did not match」,但用Azure门户生成的令牌访问同一个资源就完全正常。结合你提供的代码和错误返回的签名串,我帮你找出几个关键问题点:
1. 变量名不匹配导致签名串缺失账户名
从你给出的错误信息里可以看到,实际用于签名的字符串第一行是空的,直接从signedPermissions开始:
rwdlacupiy
bfqt
o
2023-03-08T02:23:43Z
2023-03-12T01:23:43Zhttps
2021-12-02
但按照Azure SAS签名规则,签名串的第一行必须是存储账户名。看你的代码,你定义的变量是String accountName = "<My account name>";,但在拼接stringToSign的时候用的是ACCOUNT_NAME(全大写)——Java是大小写敏感的,这会导致签名串开头直接缺失账户名,这是触发签名不匹配的核心原因。
2. 时间格式用了12小时制而非24小时制
你代码里的时间格式化用的是:
SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'hh:mm:ss'Z'");
这里的hh是12小时制的小时格式,但Azure要求的是24小时制的HH。如果你的生成时间是下午时段,12小时制的hh会把13:00变成01:00,导致签名串里的时间和实际令牌里的时间不匹配,同样会触发签名错误。
3. 其他需要验证的细节
- 确保
signedIp为空时,签名串里对应的行是空行(你的代码里已经做到了,错误信息里也有对应的空行,这部分没问题)。 - 检查存储账户密钥是否正确:确认你用的是主密钥或辅助密钥,而不是其他类型的密钥,并且复制的时候没有多带空格或换行。
修正后的代码片段
把这两个核心问题修复后,代码应该可以正常工作,这里是修正后的关键部分:
// 修正变量名:用定义好的accountName而非ACCOUNT_NAME String stringToSign = accountName + "\n" + signedPermissions + "\n" + signedService + "\n" + signedResType + "\n" + start + "\n" + expiry1 + "\n" + signedIp + "\n" + protocol + "\n" + AZURE_API_VERSION+"\n"; // 修正时间格式为24小时制的HH SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); fmt.setTimeZone(TimeZone.getTimeZone("UTC"));
验证步骤
修复后建议先打印出stringToSign的内容,和错误返回里的「String to sign used was」对比,确保两者除了账户名(现在应该正确显示)和时间格式修正外完全一致。另外也可以把生成的SAS令牌和门户生成的令牌对比参数,确认sv、ss、srt、sp、st、se这些参数都匹配。
备注:内容来源于stack exchange,提问作者user21371513

