使用Salesforce APEX生成Azure Blob SAS令牌时签名不匹配问题
排查Azure Blob SAS令牌签名不匹配问题
错误响应详情
<?xml version="1.0" encoding="utf-8"?> <Error> <Code>AuthenticationFailed</Code> <Message>Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. RequestId:b0dffeb8-701e-005c-328e-e55882000000 Time:2023-09-12T15:36:13.3757050Z</Message> <AuthenticationErrorDetail>Signature did not match. String to sign used was rac 2023-09-12T15:33:47Z 2023-09-12T15:49:47Z /blob/ittstsa/ittstsafs 2023-01-03 c </AuthenticationErrorDetail> </Error>
待排查的APEX代码
private String generateSasTokenString(final String sourceName) { final Datetime sasExpires = Datetime.now().addMinutes(15); final Datetime sasStarts = Datetime.now().addMinutes(-1); final String versionDate = '2023-01-03'; final String signedPermissions = 'rac'; final String signedStarts = sasStarts.formatGmt('YYYY-MM-dd\'T\'HH:mm:ss\'Z\''); final String signedExpires = sasExpires.formatGmt('YYYY-MM-dd\'T\'HH:mm:ss\'Z\''); final String signedService = 'c'; final String signedIdentifier = ''; final String signedIp = ''; final String signedProtocol = ''; final String rscc=''; final String rscd=''; final String rsce=''; final String rscl=''; final String rsct=''; final String stringToSign = signedPermissions + '\n' + signedStarts + '\n' + signedExpires + '\n' + '/blob/ittstsa/ittstsafs\n' + signedIdentifier + '\n' + signedIp + '\n' + signedProtocol + '\n' + versionDate + '\n' + signedService + '\n' + '\n' + rscc + '\n' + rscd + '\n' + rsce + '\n' + rscl + '\n' + rsct; System.debug('stringToSign--->'+stringToSign); final Blob unicodeKey = EncodingUtil.base64Decode('___'); final Blob blobData = Crypto.generateMac('HMACSHA256', Blob.valueOf(stringToSign), unicodeKey); System.debug('!!! ->>>' + EncodingUtil.base64Encode(blobData)); final String sasToken = EncodingUtil.urlEncode(EncodingUtil.base64Encode(blobData), 'UTF-8'); final String sasTokenString = sourceName + '?sv=' + versionDate + '&st=' + EncodingUtil.urlEncode(signedStarts, 'UTF-8') + '&se=' + EncodingUtil.urlEncode(signedExpires, 'UTF-8') + '&sr=' + signedService + '&sp=' + signedPermissions + '&sig=' + sasToken; return sasTokenString; }
核心排查点及修正方案
1. 签名字符串顺序与结构错误
Azure Blob服务SAS(版本2023-01-03)的签名字符串必须严格遵循固定顺序,你的代码在<资源类型>(signedService)后多添加了一个不必要的空行,导致签名字符串与Azure预期的结构不匹配。
修正后的签名字符串拼接代码:
final String stringToSign = signedPermissions + '\n' + signedStarts + '\n' + signedExpires + '\n' + '/blob/ittstsa/ittstsafs\n' + signedIdentifier + '\n' + signedIp + '\n' + signedProtocol + '\n' + versionDate + '\n' + signedService + '\n' + rscc + '\n' + rscd + '\n' + rsce + '\n' + rscl + '\n' + rsct;
2. 日期格式零填充验证
确认formatGmt生成的时间字符串包含两位的小时、分钟、秒(如09:05:03而非9:5:3)。当前使用的'YYYY-MM-dd\'T\'HH:mm:ss\'Z\''格式符符合要求,无需修改,但需验证实际生成的时间格式是否正确。
3. 存储账户密钥正确性
确保EncodingUtil.base64Decode('___')中的密钥是存储账户的主密钥/辅助密钥的Base64编码值,且与Java代码中使用的密钥完全一致。密钥不匹配会直接导致签名验证失败。
4. 字符串编码一致性
Azure要求签名字符串使用UTF-8编码,APEX的Blob.valueOf(stringToSign)默认使用UTF-8,需确认Java代码中也使用UTF-8编码生成签名字符串,避免编码差异导致的签名不一致。
5. 换行符格式验证
Azure要求签名字符串使用LF(\n)作为换行分隔符,APEX中使用'\n'符合要求,需确认Java代码中未使用CRLF(\r\n)作为换行符,否则会导致签名字符串内容不一致。
内容的提问来源于stack exchange,提问作者Miłosz
相关产品推荐
相关产品推荐

