Azure Storage Blob服务认证失败:PHP生成SAS令牌签名不匹配问题求助
Azure Storage Blob服务认证失败:PHP生成SAS令牌签名不匹配问题求助
我现在遇到了一个Azure Storage Blob的SAS令牌生成问题,用下面的PHP函数生成的SAS URL在浏览器里访问时总是返回AuthenticationFailed错误,提示签名不匹配。麻烦帮忙看看哪里出问题了?
function generateSasToken($accountName, $accountKey, $blobName, $containerName, $expiryTime = '+1 hour') { // Get current UTC time and expiry time (in ISO 8601 format) $start = gmdate('Y-m-d\TH:i:s\Z'); // Current time in UTC format $expiry = gmdate('Y-m-d\TH:i:s\Z', strtotime($expiryTime)); // Expiry time in UTC format // Construct the URL for the blob (to be used in SAS token) $url = "https://$accountName.blob.core.windows.net/$containerName/$blobName"; // Set SAS parameters $permissions = 'r'; // Read permissions $services = 'b'; // Blob service $resource = 'c'; // Container resource $protocol = 'https'; // Protocol (HTTPS only) $version = '2022-11-02'; // API version // Build the string to sign (format: [permissions] \n [services] \n [resource] \n [start] \n [expiry] \n [protocol] \n [version]) $stringToSign = "$permissions\n$services\n$containerName\n$start\n$expiry\n$protocol\n$version"; // Decode the account key from base64 (used for HMAC calculation) $decodedAccountKey = base64_decode($accountKey); // Generate the signature using HMAC-SHA256 $signature = base64_encode(hash_hmac('sha256', $stringToSign, $decodedAccountKey, true)); // Build the full SAS token with all required parameters $sasToken = "sv=$version&ss=$services&srt=$resource&sp=$permissions&se=$expiry&st=$start&spr=$protocol&sig=" . urlencode($signature); // Return the full SAS URL return "$url?$sasToken"; }
访问时收到的错误信息:
AuthenticationFailed
Server failed to authenticate the request. Make sure the value of Authorization header is formed correctly including the signature. ...
Signature did not match. String to sign used was ...
问题排查与修正方案
我仔细检查了代码,发现核心问题是SAS签名字符串的格式不符合Azure官方规范,同时资源类型配置和目标资源不匹配,导致签名验证失败。
关键错误点:
- 资源类型不匹配:你要生成的是单个Blob的SAS URL,但代码中设置
$resource = 'c'(容器资源),应该改为'b'(Blob资源)。 - 签名字符串格式错误:Azure Storage SAS的签名字符串有严格的字段顺序要求,针对2022-11-02版本的Blob服务,签名字符串必须包含以下字段(顺序不能乱):
你的代码错误地省略了IP范围占位位,并且错误地将容器名直接插入到字段中,完全不符合规范。<权限> <服务类型> <资源类型> <起始时间> <过期时间> <IP范围>(留空则不限制) <协议> <API版本> <资源路径>(Blob为`/$accountName/$containerName/$blobName`,容器为`/$accountName/$containerName`)
修正后的完整函数:
function generateSasToken($accountName, $accountKey, $blobName, $containerName, $expiryTime = '+1 hour') { // 获取UTC格式的起始和过期时间 $start = gmdate('Y-m-d\TH:i:s\Z'); $expiry = gmdate('Y-m-d\TH:i:s\Z', strtotime($expiryTime)); // Blob的基础访问URL $url = "https://$accountName.blob.core.windows.net/$containerName/$blobName"; // SAS参数配置(针对单个Blob的只读权限) $permissions = 'r'; // 只读权限 $services = 'b'; // 目标服务:Blob服务 $resourceTypes = 'o'; // 资源类型:对象(对应单个Blob) $resource = 'b'; // 目标资源级别:Blob $protocol = 'https'; // 仅允许HTTPS访问 $version = '2022-11-02'; // 使用的Azure Storage API版本 $ipRange = ''; // 留空表示不限制访问IP // 严格按照Azure规范构建要签名的字符串 $stringToSign = "$permissions\n" . "$services\n" . "$resourceTypes\n" . "$start\n" . "$expiry\n" . "$ipRange\n" . "$protocol\n" . "$version\n" . "/$accountName/$containerName/$blobName\n" . "\n"; // 最后两个空行对应可选的signedIdentifier和encryptionScope字段 // 解码Base64格式的账户密钥 $decodedAccountKey = base64_decode($accountKey); // 生成HMAC-SHA256签名 $signature = base64_encode(hash_hmac('sha256', $stringToSign, $decodedAccountKey, true)); // 拼接完整的SAS令牌参数 $sasToken = "sv=$version&ss=$services&srt=$resourceTypes&sp=$permissions&se=$expiry&st=$start&spr=$protocol&sr=$resource&sig=" . urlencode($signature); // 返回带SAS令牌的完整访问URL return "$url?$sasToken"; }
修正说明:
- 调整
$resource参数为'b',明确目标是单个Blob资源 - 修正
$resourceTypes为'o'(对象级资源,对应Blob) - 按照Azure规范重新构建签名字符串,补充了IP范围占位位,并且添加了正确的Blob资源路径
- SAS令牌参数中补充了
sr=$resource字段,确保参数和签名的资源类型完全匹配
备注:内容来源于stack exchange,提问作者Victor Daramola
相关产品推荐
相关产品推荐

