php - 无法在 Azure 中对帐户级别 SAS 进行身份验证
问题描述
我一直在关注Microsoft 的最新文章,以生成用于 Azure 存储服务(尤其是 Blob)的帐户级别共享访问签名 (SAS)。
每次我PUT
对我的 Blob 服务执行请求时,我都会收到一条403
响应,其中包含以下消息:
服务器未能验证请求。确保 Authorization 标头的值正确形成,包括签名。
这是我生成签名的函数:
use MicrosoftAzure\Storage\Common\Internal\StorageServiceSettings;
use MicrosoftAzure\Storage\Blob\BlobRestProxy;
public function generateUploadLink($container, $folder, $filename)
{
# get account settings
$settings = StorageServiceSettings::createFromConnectionString(AZURE_BLOB);
$accountName = $settings->getName();
$accountKey = $settings->getKey();
# define start and expire datetime stamps (ISO 8601)
$startTime = (new DateTime('GMT'))->modify('-2 days')->format('Y-m-d\TH:i:s\Z');
$expireTime = (new DateTime('GMT'))->modify('+2 days')->format('Y-m-d\TH:i:s\Z');
$parameters = [];
$parameters[] = $accountName; # account name
$parameters[] = 'wac'; # permissions
$parameters[] = 'b'; # service
$parameters[] = 'sco'; # resource type
$parameters[] = $startTime; # start time
$parameters[] = $expireTime; # expire time
$parameters[] = ''; # accepted ip's
$parameters[] = 'https,http'; # accepted protocol
$parameters[] = '2018-03-28'; # latest microsoft api version
# implode the parameters into a string
$stringToSign = utf8_encode(implode("\n", $parameters));
# decode the account key from base64
$decodedAccountKey = base64_decode($accountKey);
# create the signature with hmac sha256
$signature = hash_hmac("sha256", $stringToSign, $decodedAccountKey, true);
# encode the signature as base64
$sig = urlencode(base64_encode($signature));
# construct the sas (shared access signature)
$sas = "sv=2018-03-28&ss=b&srt=sco&sp=wac&se={$expireTime}&st={$startTime}&spr=https,http&sig={$sig}";
# create client
$blobClient = BlobRestProxy::createBlobService(AZURE_BLOB);
# generate upload link
$blobUrlWithSAS = sprintf('%s%s?%s', (string)$blobClient->getPsrPrimaryUri(), "{$container}/{$folder}/{$filename}", $sas);
# return upload link
return $blobUrlWithSAS;
}
我的输出示例如下所示 -PUT
向此 URL 发出请求时,它失败并显示上述错误消息。
https://batman.blob.core.windows.net/payroll-enroll/2019/test.txt?sv=2018-03-28&ss=b&srt=sco&sp=wac&se=2019-02-04T03:44:51Z&st=2019-01-31T03:44:51Z&spr=https,http&sig=ox7RdKGTKRYvGz2u9ScFv4TP4ZfduKxFhYdpvJKjE4A%3D
相比之下,如果我直接从 Azure 门户生成帐户级别的共享访问签名,它看起来像这样——当PUT
向这个 URL 发出请求时,它会成功。
https://batman.blob.core.windows.net/payroll-enroll/2019/test.txt?sv=2018-03-28&ss=b&srt=sco&sp=wac&se=2019-02-02T16:29:17Z&st=2019-02-02T08:29:17Z&spr=https,http&sig=omPc4ZwEdefDoHKqA4TqVOm3NUW%2BcKcNqTuD1hq94VU%3D
除了开始和过期时间之外,我认为两者之间没有区别。顺便说一句,我还要注意,我尝试使用azure-storage-php包生成服务级别 SAS,结果相同(未能验证请求)。
我已经确认或尝试过以下事情:
$accountName
并$accountKey
返回正确的值,与通过 Azure 门户看到的值相比- 尝试了
now
,UTC
, 和中的每一个GMT
作为参数DateTime()
- 在两侧提供了充足的填充(2 天),以确保它不是时差问题,正如我在 Stack 上阅读的其他问题中经常提到的那样
- 将通配符 ( ) CORS 设置应用于我的
*
存储帐户ALLOWED METHODS
,ALLOWED ORIGINS
和ALLOWED HEADERS
EXPOSED HEADERS
- 禁用
Secure transfer required
(同时允许http
, 和https
)
我难住了。
我的问题:在构建 SAS 时我做错了什么,为什么我会继续收到与身份验证相关的请求失败?
解决方案
请更改以下代码行:
$stringToSign = utf8_encode(implode("\n", $parameters));
到
$stringToSign = utf8_encode(implode("\n", $parameters) . "\n");
本质上,您需要附加一个额外的换行符。
取自此处的代码:https ://github.com/Azure/azure-storage-php/blob/master/azure-storage-common/src/Common/SharedAccessSignatureHelper.php 。
推荐阅读
- python - 使用 sklearn.neighbors.ball_tree.BinaryTree.query_radius 时出现 MemoryError
- angular - NullInjectorError: R3InjectorError(AppModule)[Router -> Router -> Router]: NullInjectorError: No provider for Router
- kubernetes - 使用 helm 部署应用程序后,面对错误 pod 具有未绑定的立即 PersistentVolumeClaims 附加 pvc
- java - 保存包时出错:/xl/sharedStrings.xml 部分无法使用编组器保存在流中
- ios - 线程 1:“-[Xylophone.ViewController buttonClicked:]:无法识别的选择器发送到实例 0x7ff83a6074e0”
- javascript - 如何通过编译错误停止推送?
- html - 自动填充网格容器,其中一项全宽不留空隙
- mysql - 如何在 typeorm 和 nest.js 中设置布尔验证
- python - model.summary() 的输出与预期的 tensorflow 2 不同
- javascript - 如何在javascript中以固定间隔创建计时器?以及从数字开始的选项?