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

使用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---&gt;'+stringToSign);
        final Blob unicodeKey = EncodingUtil.base64Decode('___');
        final Blob blobData = Crypto.generateMac('HMACSHA256', Blob.valueOf(stringToSign), unicodeKey);
        System.debug('!!! -&gt;&gt;&gt;' + EncodingUtil.base64Encode(blobData));
        final String sasToken = EncodingUtil.urlEncode(EncodingUtil.base64Encode(blobData), 'UTF-8');
        final String sasTokenString = sourceName + '?sv=' + versionDate + '&amp;st=' + EncodingUtil.urlEncode(signedStarts, 'UTF-8') + '&amp;se=' + EncodingUtil.urlEncode(signedExpires, 'UTF-8') + '&amp;sr=' + signedService  + '&amp;sp=' + signedPermissions + '&amp;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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 08:58:10