解决 Gateway+Minio SignatureDoesNotMatch异常

1,087 阅读2分钟

前提

为某XX私有化部署一整套系统,部署内容如下(均Docker部署

  • SpringBoot + SpringCloud 一套微服务(包含Gateway)
  • Minio
  • Mysql 等等

由于甲方要求一切文件系统都要存放至本地,并要进行请求接口的鉴权(不能A用户能看到B用户的请求),所以并没有开放Minio端口,仅是在容器内部调用

上传文件下载文件都需要其他容器内在内网使用http://minio:9001 去操作

上传文件

例如客户从小程序上传一张图片,那么流程为

小程序拍照 / 上传至后端接口 --->
Gateway路由解析,转发至 File服务 --->
File服务接受文件后,指定 Minio 的端口(minio:9100),以及AK,进行文件上传 --->
File服务将上传完的图片获取临时链接,返回给小程序,完成。

这里与Minio之间的所有交互,上传与获取路径,都是在File服务内做的,一切环境都是在内网,没有问题

预览文件

流程为

小程序通过某接口获取文件在数据库中存放的地址,例如 http://xxx.com/minio/xxx/userId/x-x-x.png --->
小程序请求 minio文件,那么通过xxx.com会直接访问到 Gateway 服务 --->
Gateway 服务根据 url中的minio判断是文件请求,转向到 minio:9001 ---> 
至此,通过xxx.com/minio/xxx 就可以直接访问到 xxx.png

Gateway 中的配置

- id: minio-xxx
  uri: http://minio:9000
  predicates:
    - Path=/minio/face/**
  filters:
    - PreserveHostHeader=true

请求确实请求到了 minio,但是会报异常

<Error> 
    <Code>SignatureDoesNotMatch</Code> 
    <Message> The request signature we calculated does not match the signature you provided. Check your key and signing method </Message> 
    <Resource>xxx.jpg</Resource> 
    <RequestId>xxxxxxxxxx</RequestId> 
    <HostId>xxxxx-xxxxxx-xxxxxx-xxxxx-xxxx</HostId> 
</Error>

大概意思为,请求参数时携带的数据,与Minio中的签名校验不匹配导致。

其中查找了很多参考文献,其中两篇为我提供了很大思路

1 minio报错:403错误,预览PDF页面一直转圈

2 MinIO Kubernetes Signature Error

其他的大部分文章遇到的此类问题,大多都是K8s 或者 Nginx代替我的场景中的Gateway,所出现问题,猜测一切的病灶都来源于请求头

所以我在我的 Gateway Filter中,将Minio的请求中的HOST,均修改为

ServerHttpRequest modifiedRequest = exchange.getRequest()
        .mutate()
         // 设置正确的 Host 头
        .headers(httpHeaders -> httpHeaders.set("Host", "minio:9000")) 
        .build();

问题结束,主要的发现问题原因的地方在于上面两篇文章让我猜测到问题的原因既然是签名问题,那么肯定是请求参数 OR 请求头。