Spring Cloud Gateway路由到Amazon S3签名失败处理

news2024/11/26 21:47:14

Spring Cloud Gateway路由到Amazon S3签名失败处理

背景

最近在预研统一存储网关,想到就是使用Spring Cloud Gateway作为网关的入口,再反向代理到S3对象存储服务器。

软件版本

网关:Spring Cloud Gateway 3.1.2

s3对象存储:minio

aws java sdk:1.12.429

问题现象

Spring Cloud Gateway的路由配置规则如下:

spring:
  cloud:
    gateway:
      routes:
        - id: s3-route
          uri: s3-endpiont
          predicates:
            - Path=/s3/**
          filters:
            - StripPrefix=1
            - PreserveHostHeader

我添加了两个过滤器,一个是StripPrefix这个过滤器,它有一个parts参数,它的作用是重新设置路由后的路径,比如我的请求是 gateway-host/s3/,parts参数设置为1的话,路由之后的路径会变成s3-endpiont,它会截取掉请求路径中的前缀,这个可以保证我们能够路由到准确的s3-endpoint地址。

还有一个过滤器是PreserveHostHeader,这个过滤器的作用是保留请求的Host头,如果不设置的话,请求经过网关路由之后Host头会变成uri对应的地址,这个也会导致S3签名校验失败,这边可以参考nginx转发到Amazon S3的配置,参考地址:https://stackoverflow.com/questions/53833505/nginx-confg-issue-couldnt-connect-to-s3-compatible-storage-from-nodejs-test-p

sdk调用如下,获取所有桶的接口:

public static void main(String[] args) {
  ClientConfiguration config = new ClientConfiguration().withProtocol(Protocol.HTTP);
  config.setSignerOverride("S3SignerType");
  AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
    .withClientConfiguration(config)
    .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("minioadmin", "minioadmin")))
    .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://10.1.140.3:8777/s3", null))
    .build();
  final List<Bucket> buckets = amazonS3.listBuckets();
  System.out.println(buckets);
}

在客户端调用请求时,会抛出异常,然后带着问题去搜索了一下解决方案。
在这里插入图片描述

原因以及解决方案

先Google了一下,没有找到合适的解决方案,StackOverFlow上面有类似的问题,参考:https://stackoverflow.com/questions/75834957/spring-cloud-gateway-to-s3-signaturedoesnotmatch/76097374,但是没有人回答(下面那个答案是我后来加上的~)。

然后把问题现象和ChatGPT描述了一下,得到了一些答案:
在这里插入图片描述
想到可以是StripPrefix过滤器修改了’Host’请求头,所以将StripPrefix过滤器去掉,最后配置如下:

spring:
  cloud:
    gateway:
      routes:
        - id: s3-route
          uri: s3-endpiont
          predicates:
            - Path=/**
          filters:
            - PreserveHostHeader

sdk调用:

public static void main(String[] args) {
    ClientConfiguration config = new ClientConfiguration().withProtocol(Protocol.HTTP);
    config.setSignerOverride("S3SignerType");
    AmazonS3 amazonS3 = AmazonS3ClientBuilder.standard()
            .withClientConfiguration(config)
            .withCredentials(new AWSStaticCredentialsProvider(new BasicAWSCredentials("minioadmin", "minioadmin")))
            .withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration("http://10.1.140.3:8777", null))
            .build();
    final List<Bucket> buckets = amazonS3.listBuckets();
    System.out.println(buckets);
}

果然这次调用成功了:
在这里插入图片描述
但是按照上面的解决方案,不能够自定义访问的路径,其实还没有完全解决我的问题,再问一次ChatGPT:
在这里插入图片描述
回答中提到用自定义过滤器使用正确的’Host’头重新生成一份签名,我参考了GPT的回答还有查询了一些资料,写了生成签名的过滤器,代码参考如下(这边使用的签名算法是V2版本的,不同的版本应该需要不同的适配):

/**
 * 重新生成S3签名过滤器
 *
 * @author yuanzhihao
 * @since 2023/5/5
 */
@Component
@Slf4j
public class AWSSignGatewayFilterFactory extends AbstractGatewayFilterFactory<AWSSignGatewayFilterFactory.Config> {

    public AWSSignGatewayFilterFactory() {
        super(Config.class);
    }

    @Override
    public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            DefaultRequest<Void> defaultRequest = regenerateAuthorization(config, exchange);
            ServerHttpRequest request = exchange.getRequest().mutate()
                    .headers(httpHeaders -> {
                        httpHeaders.set("Authorization", defaultRequest.getHeaders().get("Authorization"));
                        httpHeaders.set(Headers.DATE, defaultRequest.getHeaders().get(Headers.DATE));
                    })
                    .build();
            return chain.filter(exchange.mutate().request(request).build());
        };
    }


    // 重新计算并设置签名
    private DefaultRequest<Void> regenerateAuthorization(Config config, ServerWebExchange exchange) {
        AWSCredentials credentials = new BasicAWSCredentials(config.getAk(), config.getSk());
        DefaultRequest<Void> request = new DefaultRequest<>("Amazon S3");
        request.addHeader("Host", config.getEndpoint());
        // 这边把请求头全部带下去
        exchange.getRequest().getQueryParams().forEach((key, value) -> request.addParameter(key, value.get(0)));
        exchange.getRequest().getHeaders().forEach((key, value) -> request.addHeader(key, value.get(0)));
        String path = exchange.getRequest().getURI().getPath();
        String method = Objects.requireNonNull(exchange.getRequest().getMethod(), "Method is null").toString();
        request.setResourcePath(path);
        try {
            request.setEndpoint(new URI(config.getEndpoint()));
        } catch (URISyntaxException e) {
            log.error("URI error", e);
            throw new RuntimeException(e);
        }
        S3Signer signer = new S3Signer(method, path);
        signer.sign(request, credentials);
        return request;
    }


    @Override
    public List<String> shortcutFieldOrder() {
        return Arrays.asList("endpoint", "ak", "sk");
    }

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public static class Config {
        private String endpoint;
        private String ak;
        private String sk;
    }
}

配置文件中生效过滤器:

s3:
  endpoint: http://10.1.140.3:9000
  ak: minioadmin
  sk: minioadmin

spring:
  cloud:
    gateway:
      routes:
        - id: s3-route
          uri: ${s3.endpoint}
          predicates:
            - Path=/**
          filters:
            - PreserveHostHeader
            - StripPrefix=1
            - AWSSign=${s3.endpoint},${s3.ak},${s3.sk}

调用成功:
在这里插入图片描述
基于上面的验证,后续其实就可以实现标准的S3协议,同时也可以很方便的对S3进行扩展,比如限流限速,对S3用户权限进行扩展等等能力。

结语

ChatGPT真的很厉害,它确实可以帮助我们解决很多问题。

代码地址:https://github.com/yzh19961031/blogDemo/tree/master/s3-gateway

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/529280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

语音识别 | kaggle鸟叫识别新赛赛题解析

整理自kaggle平台 赛题题目&#xff1a; BirdCLEF 2023 kaggle - 鸟声识别大赛 赛题链接&#xff1a;https://www.kaggle.com/competitions/birdclef-2023 赛题背景 鸟类是生物多样性变化的极好指标&#xff0c;因为它们具有高度流动性并且具有多样化的栖息地要求。因此物种…

Jmeter和Postman那个工具更适合做接口测试?

软件测试行业做功能测试和接口测试的人相对比较多。在测试工作中&#xff0c;有高手&#xff0c;自然也会有小白&#xff0c;但有一点我们无法否认&#xff0c;就是每一个高手都是从小白开始的&#xff0c;所以今天我们就来谈谈一大部分人在做的接口测试&#xff0c;小白变高手…

推特运营的方法

推特是一个广泛使用的社交媒体平台&#xff0c;可以通过以下方法来运营和营销&#xff1a; 建立一个完整的个人或品牌资料&#xff1a;确保你的推特资料页面清晰、有吸引力&#xff0c;并包含关键信息&#xff0c;如个人简介、网站链接和联系方式。 确定目标受众&#xff1a;…

【重制版】10分钟学会WINDOWS、MAC、LINUX如何安装GPT桌面版

文章目录 1 前言2 Windows版下载安装2.1 安装包2.2 winget下载 &#xff08;注意看&#xff0c;不是wget&#xff01;&#xff09; 3 Mac版下载安装3.1 安装包3.2 homebrew安装 4 Linux版下载安装4.1 安装包4.2 终端下载 5 特点5.1 软件特点5.2 菜单功能&#xff08;个人喜好特…

ChatGPT:【万能话术模板】+99个提示词

一&#xff1a;万能话术提示模板 【方便观看版】 【方便复制版】 现在你是一位[ ]创作者。你的任务是以[ ]为标题写一份[ ]的文章。 文章内容包含[ ] [ ] [ ]3部分。 听众是 [ ]&#xff0c;他们喜欢 [ ]&#xff0c;看重[ ]。 你的写作风…

python3 爬虫相关学习2:网页相关基础知识笔记

1 网页的构成 一般来说&#xff0c;日常看到的网站的网页的组成内容有如下 html 结构的代码css 结构的代码资源&#xff08;文字&#xff0c;图片&#xff0c;音乐&#xff0c;视频等等&#xff09; html 网页结构描述的语言 比如这种写法的文件 <html> <body> …

机器学习基础知识之分类性能评价指标

文章目录 分类性能基本概念1、准确率1、精确率2、召回率3、F1-score4、ROC曲线5、多分类问题中的相关指标6、混淆矩阵 分类性能基本概念 与预测性能评价指标相类似&#xff0c;分类性能评价指标同样也是将模型计算得出的标签值与实际的真实标签值通过数学统计上的公式进行计算…

十三、超时重试机制

目录 超时配置和重试机制 FeignClient 、Ribbon 、 Hystrix三个之间配置优先级的关系 配置常用属性 Ribbon超时和重试配置: Ribbon重试次数计算公式&#xff1a; FeignClient 超时配置&#xff1a; Hystrix超时配置&#xff1a; Hystrix超时计算公式&#xff1a; 超时配…

Android PickerView简单应用

1. Android-PickerView Android-PickerView这是一款仿iOS的PickerView控件&#xff0c;有时间选择器和选项选择器。 添加依赖项 implementation com.contrarywind:Android-PickerView:4.1.92. 时间选择器 Android-PickerView时间选择器使用Build模式来创建 var timePicker…

如何开展计算机相关的学术研究? - 易智编译EaseEditing

计算机科学是一门包括理论和应用两方面的学科&#xff0c;可以涉及各种领域&#xff0c;如人工智能、计算机视觉、机器学习、大数据、网络安全等等。开展计算机相关的学术研究需要以下步骤&#xff1a; 1.明确研究问题&#xff1a; 首先需要明确研究问题和目标。选择一个研究方…

5月15号软件资讯更新合集.....

Vue2 to Composition API 语法转换器 V2.0 版本更新 在线使用 网站 Gitee: vue2-to-composition-api vue2-to-composition-api 是一款可以将 Options API 转换成 Composition API 的在线应用工具&#xff0c;转换后直接导出 Script setup 内容&#xff0c;帮助 Vue2 项目减少…

VoxWeekly|The Sandbox 生态周报(20230508)

欢迎来到由 The Sandbox 制作的《VoxWeekly》。我们会在每周一发布这份周报&#xff0c;对上一周 The Sandbox 生态系统所发生的事情进行总结。 如果你喜欢我们内容&#xff0c;欢迎与朋友和家人分享。您还可以订阅我们的 Medium 、关注我们的 Twitter&#xff0c;并加入 Disco…

OpenCL编程指南-4.2矢量数据类型

矢量数据类型 OpenCL C还增加了对矢量数据类型的支持。矢量数据类型如下定义&#xff0c;首先是类型名&#xff0c;具体包括char、uchar、short、ushort、int、uint、float、long或ulong&#xff0c;后面是一个字面值n来定义矢量中的元素个数。对于所有矢量数据类型&#xff0…

ANR原理篇 - ANR信息收集过程

系列文章目录 提示&#xff1a;这里可以添加系列文章的所有文章的目录&#xff0c;目录需要自己手动添加 例如&#xff1a;第一章 Python 机器学习入门之pandas的使用 文章目录 系列文章目录前言一、ANR日志信息收集过程ANR日志收集完整流程1.1 logcat中信息记录1.2 trace.txt文…

《微服务实战》 第九章 Gitlab使用

前言 微服务项目&#xff0c;常常需要多人协作完成工作&#xff0c;本章教程是介绍Gitlab使用&#xff0c;使多人协作告别低端的手动拷贝&#xff0c;也告别传统的SVN。 1、下载安装git https://git-scm.com/download/win 1.1、安装好以后&#xff0c;cmd中输入git 2、生成…

什么是Docker 【微服务框架】

Docker Docker如何解决依赖的兼容问题&#xff1f; 将应用的Libs&#xff08;函数库&#xff09;、Deps&#xff08;依赖&#xff09;、配置与应用一起打包将每个应用放到一个隔离容器去运行&#xff0c;避免互相干扰 不同环境的操作系统不同&#xff0c;Docker如何解决&#…

(数字图像处理MATLAB+Python)第八章图像复原-第一、二节:图像复原概述和图像退化模型

文章目录 一&#xff1a;图像复原概述二&#xff1a;图像退化模型&#xff08;1&#xff09;连续退化模型&#xff08;2&#xff09;离散退化模型 三&#xff1a;图像退化函数的估计&#xff08;1&#xff09;基于模型的估计法&#xff08;2&#xff09;运动模糊退化估计 一&am…

理解JS的事件循环机制(Event Loop)

文章目录 一、前言二、首先理解三、灵魂三问1. JS为什么是单线程的?2. 为什么需要异步? &#xff08;为什么要有事件循环机制&#xff1f;&#xff09;3. 单线程又是如何实现异步的呢? 四、什么是事件循环&#xff1f;五、事件循环&#xff08;Event Loop &#xff09;执行顺…

哈工大软件架构与中间件作业1

《软件架构与中间件》作业1报告 ——作业1&#xff1a;软件架构 姓名&#xff1a; 石卓凡 学号&#xff1a; 120L021011 目录 项目介绍......................................................................................................…

混淆(Proguard R8)和反混淆

本篇来介绍下Android的混淆和反混淆&#xff0c;说起混淆&#xff0c;大家都会很自然地想到Proguard&#xff0c;此外还有R8。事实上&#xff0c;AGP3.3之后&#xff0c;官方默认使用R8做代码优化、混淆和压缩。ProGuard和R8常常用于混淆最终的Android项目&#xff0c;增加项目…