使用Node.js生成Azure存储SAS URL时遭遇认证失败问题
问题:生成Azure Blob存储SAS URL用于前端直接上传时签名不匹配错误
我尝试生成SAS URL返回给客户端,让客户端通过该URL直接PUT文件到Azure Blob存储,但一直遇到签名不匹配的认证错误。
我的后端端点代码(update 1):
router.get('/get-upload-url', async (req, res) => { const blobName = 'dummyBlobName.jpeg'; const blobServiceClient = new BlobServiceClient(`https://${ACCOUNT_NAME}.blob.core.windows.net`, new StorageSharedKeyCredential(ACCOUNT_NAME, SAS_TOKEN)); const containerClient = blobServiceClient.getContainerClient(CONTAINER_NAME); const blockBlobClient = containerClient.getBlockBlobClient(blobName); const startDate = new Date(); const expiryDate = new Date(startDate); expiryDate.setMinutes(startDate.getMinutes() + 100); const sasToken = generateBlobSASQueryParameters({ containerName: CONTAINER_NAME, blobName, permissions: BlobSASPermissions.parse('cw'), startsOn: startDate, expiresOn: expiryDate }, blobServiceClient.credential); const sasUrl = `${blockBlobClient.url}?${sasToken}`; res.json({ sasUrl }); }); app.use('/', router); app.listen(PORT, () => { console.log(`Server running on port ${PORT}`); });
我用以下curl命令测试:
curl -X PUT -T ~/Downloads/dp.jpeg \ -H "x-ms-date: $(date -u)" \ -H "x-ms-blob-type: BlockBlob" \ "https://appstrolabstoragedev.blob.core.windows.net/imgx/dummyBlobName.jpeg?sv=2024-08-04&st=2024-07-29T12%3A52%3A55Z&se=2024-07-29T14%3A32%3A55Z&sr=b&sp=cw&sig=jsYb6VOm57avYu2eS2H26Q6vMkzSjdnjMI%2B80xygQ%2F8%3D"
得到的错误信息:
<?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:beee57d1-201e-005b-7db6-e1f5de000000 Time:2024-07-29T12:53:12.7097016Z</Message><AuthenticationErrorDetail>Signature did not match. String to sign used was cw 2024-07-29T12:52:55Z 2024-07-29T14:32:55Z /blob/appstrolabstoragedev/imgx/dummyBlobName.jpeg 2024-08-04 b </AuthenticationErrorDetail></Error>%
我已经把blobName更新为'dummyBlobName.jpeg',但还是报错:
<?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:03849c77-001e-0087-46c0-e15f80000000 Time:2024-07-29T14:06:41.0301691Z</Message><AuthenticationErrorDetail>Signature did not match. String to sign used was cw 2024-07-29T14:05:50Z 2024-07-29T15:45:50Z /blob/appstrolabstoragedev/imgx/dummyBlobName.jpeg 2024-08-04 b </AuthenticationErrorDetail></Error>%
解决方案
核心问题:你错误地将SAS_TOKEN传入了StorageSharedKeyCredential,这个类需要的是存储账户的访问密钥(而非SAS令牌)。生成SAS签名必须使用账户密钥,SAS令牌是客户端用于访问的最终凭证,不能用来生成新的SAS。
具体修复步骤
- 替换凭证参数:把代码中的
SAS_TOKEN替换为存储账户的访问密钥(可在Azure门户的「存储账户」→「访问密钥」页面获取)。 - 日期处理优化:确保日期是UTC时间且去掉毫秒,避免签名时的细微时间差导致验证失败:
const startDate = new Date(Date.now()); startDate.setMilliseconds(0); // 移除毫秒部分 const expiryDate = new Date(startDate); expiryDate.setMinutes(startDate.getMinutes() + 100); - 简化测试命令:使用SAS URL上传时,不需要添加
x-ms-date请求头,Azure会通过SAS中的st(起始时间)和se(过期时间)验证请求有效性,去掉该头后重新测试:curl -X PUT -T ~/Downloads/dp.jpeg \ -H "x-ms-blob-type: BlockBlob" \ "你的SAS_URL"
修复后的核心代码
// 使用账户密钥而非SAS_TOKEN创建StorageSharedKeyCredential const blobServiceClient = new BlobServiceClient( `https://${ACCOUNT_NAME}.blob.core.windows.net`, new StorageSharedKeyCredential(ACCOUNT_NAME, ACCOUNT_KEY) // 这里替换为ACCOUNT_KEY );
额外建议
- 不要硬编码账户密钥,使用环境变量管理(如
process.env.AZURE_STORAGE_ACCOUNT_KEY),避免密钥泄露。 - 合理设置SAS有效期,根据业务场景调整,避免过长有效期带来的安全风险。
内容的提问来源于stack exchange,提问作者Arnob
相关产品推荐
相关产品推荐

