使用Laravel Storage的directories方法访问Minio时出现SignatureDoesNotMatch错误
问题场景
我尝试用以下代码获取Minio存储桶中的文件夹列表:
public function handle() { $baseDirectory = 'product/'; $directories = Storage::disk('minio')->directories($baseDirectory); }
运行代码时触发403权限错误,具体报错信息如下:
Error executing "ListObjects" on "https://some-url.id/documents?prefix=product%2F&delimiter=%2F&encoding-type=url"; AWS HTTP error: Client error:
GET https://some-url.id/documents?prefix=product%2F&delimiter=%2F&encoding-type=urlresulted in a403 Forbiddenresponse:The request signature we calcul (truncated...)return (<Code>SignatureDoesNotMatch</Code>)
SignatureDoesNotMatch (client): The request signature we calculated does not match the signature you provided. Check your key and signing method. -The request signature we calculated does not match the signature you provided. Check your key and signing method.documents/documents/177C6CAFC2C79AD5c4b4d170-8dc4-4249-9ccc-87a889a1227creturn (<Code>SignatureDoesNotMatch</Code>)
但使用makeDirectory方法创建文件夹时,代码却能正常运行:
public function handle() { // 这段代码运行正常 $baseDirectory = 'product/'; $directories = Storage::disk('minio')->makeDirectory($baseDirectory); }
我原本怀疑是Minio策略配置问题,但当前策略已包含s3:ListBucket、s3:PutObject、s3:GetObject等操作权限,资源覆盖了桶本身和桶内所有对象,理论上应该支持directories方法。
可能原因及解决方案
1. 签名计算逻辑差异
directories方法调用的是Minio的ListObjects接口,而makeDirectory本质是创建一个名为product/的空对象(Minio的文件夹是模拟实现),对应PutObject操作。两者的签名计算逻辑存在差异:
- 显式在Laravel的Minio配置中指定签名版本为
v4,确保与Minio服务器兼容:
// config/filesystems.php 中的minio配置项 'minio' => [ 'driver' => 's3', 'key' => env('MINIO_KEY'), 'secret' => env('MINIO_SECRET'), 'region' => env('MINIO_REGION', 'us-east-1'), 'bucket' => env('MINIO_BUCKET'), 'endpoint' => env('MINIO_ENDPOINT'), 'use_path_style_endpoint' => true, 'signature_version' => 'v4', // 强制指定签名版本 ],
2. 策略资源匹配细节
ListObjects属于桶级权限,需要确保策略中明确授权桶本身的s3:ListBucket操作。检查你的策略是否包含:
{ "Effect": "Allow", "Action": "s3:ListBucket", "Resource": "arn:aws:s3:::documents" }
如果策略仅授权了arn:aws:s3:::documents/*,则ListBucket权限不生效,因为该资源路径针对的是桶内对象,而非桶本身。
3. 路径格式问题
尝试去掉$baseDirectory结尾的斜杠,改为$baseDirectory = 'product'后调用directories方法。部分情况下,Minio对前缀的斜杠处理会影响签名计算或权限匹配。
4. 权限验证与测试
- 用Minio客户端直接测试
ListObjects操作,排除Laravel驱动的问题:
mc ls your-minio-alias/documents/product/
- 检查Minio服务器的日志,查看签名不匹配的具体细节(比如请求时间、签名算法是否一致)。
- 确认当前使用的Access Key是否正确关联了目标策略,避免出现策略未绑定到用户的情况。
内容的提问来源于stack exchange,提问作者Mike

