码农知识堂 - 1000bd
  •   Python
  •   PHP
  •   JS/TS
  •   JAVA
  •   C/C++
  •   C#
  •   GO
  •   Kotlin
  •   Swift
  • [Spring Cloud] GateWay自定义过滤器/结合Nacos服务注册中心


    ✨✨个人主页:沫洺的主页

    📚📚系列专栏: 📖 JavaWeb专栏📖 JavaSE专栏 📖 Java基础专栏📖vue3专栏 

                               📖MyBatis专栏📖Spring专栏📖SpringMVC专栏📖SpringBoot专栏

                               📖Docker专栏📖Reids专栏📖MQ专栏📖SpringCloud专栏     

    💖💖如果文章对你有所帮助请留下三连✨✨

    衔接上篇: [Spring Cloud] GateWay服务网关_沫洺的博客-CSDN博客

    🍁自定义全局过滤器

    官方定义全局过滤器示例

    接下来仿照示例创建我们自己的全局过滤器 

    需求: 进行token验证(网关可以理解为一个交换机,有request和response),将原来的request通过验证并解析,过滤后构建新的request来正常调用后方的具体接口

    子模块:spring-cloud-gateway

    pom添加个hutool依赖

    1. cn.hutool
    2. hutool-all

    application.properties

    1. spring.cloud.gateway.routes[0].id = route1
    2. spring.cloud.gateway.routes[0].predicates[0] = Path=/test/**
    3. spring.cloud.gateway.routes[0].filters[0] = StripPrefix=1
    4. spring.cloud.gateway.routes[0].uri = http://httpbin.org

    解析对象UserInfo

    1. @Data
    2. public class UserInfo {
    3. private Integer userId;
    4. private String nickName;
    5. }

    全局过滤器 CustomGlobalFilter

    1. @Component
    2. public class CustomGlobalFilter implements GlobalFilter, Ordered {
    3. //密钥
    4. private static final String TOKEN_SECRET="moming123";
    5. @Bean
    6. public GlobalFilter customFilter(){
    7. return new CustomGlobalFilter();
    8. }
    9. @Override
    10. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    11. ServerHttpRequest request = exchange.getRequest();
    12. ServerHttpResponse response = exchange.getResponse();
    13. //获取请求头Authorization存放的JWT结构的token数据
    14. List tokenList = request.getHeaders().get("Authorization");
    15. //如果为空,报401异常
    16. if(ObjectUtil.isEmpty(tokenList)){
    17. response.setStatusCode(HttpStatus.UNAUTHORIZED);
    18. return response.setComplete();
    19. }
    20. //不为空则获取token
    21. String token = tokenList.get(0);
    22. boolean isTrue = false;
    23. try {
    24. //验证密钥
    25. isTrue = JWTUtil.verify(token, TOKEN_SECRET.getBytes());
    26. } catch (Exception e) {
    27. e.printStackTrace();
    28. }
    29. //不匹配报401
    30. if(isTrue==false){
    31. response.setStatusCode(HttpStatus.UNAUTHORIZED);
    32. return response.setComplete();
    33. }
    34. //解析token
    35. final JWT jwt = JWTUtil.parseToken(token);
    36. //获取JWT负载部分,转成UserInfo对象
    37. //System.out.println(jwt.getPayload().toString());
    38. UserInfo userInfo = JSONUtil.toBean(jwt.getPayloads().toString(), UserInfo.class);
    39. Integer userId = userInfo.getUserId();
    40. //将userId通过header传到后端
    41. //原来的request是只读的,需要通过mutate复制一份新的request2 并添加请求头
    42. ServerHttpRequest request2 = request.mutate().header("userId", String.valueOf(userId)).build();
    43. //可以正常调用后方的具体接口
    44. //交换机也是不能改动所以复制一份,并发送新的request2
    45. return chain.filter(exchange.mutate().request(request2).build());
    46. }
    47. @Override
    48. public int getOrder() {
    49. //越小优先级越高
    50. return -1;
    51. }
    52. }

    通过启动类生成一个JWT结构的token

    1. @SpringBootApplication
    2. public class GatewayApp {
    3. public static void main(String[] args) {
    4. SpringApplication.run(GatewayApp.class, args);
    5. Map map = new HashMap<>();
    6. map.put("userId", 1);
    7. map.put("nickName", "moming");
    8. map.put("expire_time", System.currentTimeMillis()+1000*60*60*24*5);
    9. String token = JWTUtil.createToken(map, "moming123".getBytes());
    10. System.out.println(token);
    11. }
    12. }

    运行

    eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuaWNrTmFtZSI6Im1vbWluZyIsImV4cGlyZV90aW1lIjoxNjY5NjMxMDcxNDE4LCJ1c2VySWQiOjF9.wJqasnKRQwdB-u-pm6hzqcTlfRQwX2ioHHmROspBt7Q

    token错误场景

    JWT回顾:[SpringBoot-vue3]用户登录实现JWT单点登录/ThreadLocal保存用户信息_沫洺的博客-CSDN博客参考博文: JSON Web Token 入门教程

    🍂自定义网关(局部)过滤器

    局部过滤器是只针对某个网关(路由)去生效

    全局过滤器实现的是GlobalFilter,而局部过滤器实现的是GatewayFilter

    定义一个局部过滤器

    需求: 呈现网关调用接口耗时

    这里网关调用接口服务时是异步的,比如说网关通过某个线程1去访问a服务,访问结束后返回数据时走的又是另外一个线程2,所以是异步的

    那么我们要统计耗时开始时间就不能通过线程1来统计(原因是线程1可能去调用其他服务,会设置新的开始时间,),但交换机只有一个,所以可以给交换机设置一个属性开始时间戳,交换机开始作用到调用结束就是网关调用接口的耗时

    1. @Slf4j
    2. public class LoggerGatewayFilter implements GatewayFilter, Ordered {
    3. @Override
    4. public Mono filter(ServerWebExchange exchange, GatewayFilterChain chain) {
    5. //开始调用
    6. //设置开始时间戳
    7. exchange.getAttributes().put("start",System.currentTimeMillis());
    8. ServerHttpRequest request = exchange.getRequest();
    9. ServerHttpResponse response = exchange.getResponse();
    10. //过滤之后then异步执行一个方法
    11. return chain.filter(exchange).then(Mono.fromRunnable(()->{
    12. //运行结束
    13. long end = System.currentTimeMillis();
    14. long start = exchange.getAttribute("start");
    15. long msTime = end - start;
    16. //获取接口
    17. String rawPath = request.getURI().getRawPath();
    18. log.info("接口:{} -> 耗时:{}",rawPath,msTime);
    19. }));
    20. }
    21. @Override
    22. public int getOrder() {
    23. return -1;
    24. }
    25. }

    但是局部过滤器不能像全局过滤器那样定义完放到springioc中就可以使用,要通过工厂来将我们自定义的局部过滤器生产出来,而且既然是局部的,那必然要配置指定的网关去生效,来达到按需加载的效果

    配置时有个命名规则

    参考内置的局部过滤器的类的命名方式及配置的命名方式

    AddRequestHeaderGatewayFilterFactory======>AddRequestHeader

    AddRequestParameterGatewayFilterFactory======>AddRequestParameter

    所以我们自定义时的类名要加GatewayFilterFactory,配置时用前面部分即可

    比如我们自定义的LoggerGatewayFilterFactory ======>Logger

    1. @Component
    2. public class LoggerGatewayFilterFactory extends AbstractGatewayFilterFactory {
    3. @Override
    4. public GatewayFilter apply(Object config) {
    5. return new LoggerGatewayFilter();
    6. }
    7. }
    8. 配置

      1. spring.cloud.gateway.routes[0].id = route1
      2. spring.cloud.gateway.routes[0].predicates[0] = Path=/test/**
      3. spring.cloud.gateway.routes[0].filters[0] = StripPrefix=1
      4. spring.cloud.gateway.routes[0].filters[1] = Logger
      5. spring.cloud.gateway.routes[0].uri = http://httpbin.org

      注释掉自定义全局过滤器相关内容,运行访问

      🌾结合Nacos服务注册中心

      注释掉局部过滤器相关内容

      调用a服务

      添加依赖

      1. <dependency>
      2. <groupId>com.alibaba.cloudgroupId>
      3. <artifactId>spring-cloud-starter-alibaba-nacos-discoveryartifactId>
      4. dependency>

      配置nacos

      1. #与nacos服务注册中心结合
      2. spring.cloud.gateway.routes[1].id = route_nacos
      3. spring.cloud.gateway.routes[1].predicates[0] = Path=/nacos-a/**
      4. spring.cloud.gateway.routes[1].filters[0] = StripPrefix=1
      5. #前置过滤器
      6. spring.cloud.gateway.routes[1].filters[1] = AddRequestHeader=name,moming
      7. spring.cloud.gateway.routes[1].uri = lb://nacos-a

      启动nacos服务器

      修改子模块spring-cloud-nacos-a

      1. @RestController
      2. public class UserServiceController implements IUserService {
      3. @Value("${server.port}")
      4. private String port;
      5. @Override
      6. public String getName(Integer id) {
      7. HttpServletRequest request = ((ServletRequestAttributes) (RequestContextHolder.currentRequestAttributes())).getRequest();
      8. String name = request.getHeader("name");
      9. return StrUtil.format("nacos a({}) header:{} 返回的id: {}" ,this.port,name,id);
      10. }
      11. @Override
      12. public Integer getAmount(Integer id) {
      13. return id*100;
      14. }
      15. @Override
      16. public String getSleep(Integer time) {
      17. ThreadUtil.sleep(time*1000);
      18. return StrUtil.format("nacos a({}) 睡眠了 {} 秒",this.port ,time);
      19. }
      20. }

      打包运行a服务

       准备工作做完,直接运行访问

       在启动一个a服务

      访问

       

    9. 相关阅读:
      谷歌Chrome 100正式版发布:启用全新图标,修复28个安全漏洞
      [黑马程序员SpringBoot2]——基础篇2
      离子苯基卟啉交联聚苯乙烯微球/表面修饰温敏型二乙基二硫代氨基甲酸钠相关研究
      振弦采集模块数字接口
      OpenRoads地形模型添加(增补)地形点
      读书笔记:彼得·德鲁克《认识管理》第11章 若干例外及经验教训
      【Transformers】第 3 章:Transformers剖析
      Linux:信号
      ggcor替代包:linkET,相关图,mantel test可视化
      【C++】C++中的IO流
    10. 原文地址:https://blog.csdn.net/HeyVIrBbox/article/details/128003272
      • 最新文章
      • 攻防演习之三天拿下官网站群
        数据安全治理学习——前期安全规划和安全管理体系建设
        企业安全 | 企业内一次钓鱼演练准备过程
        内网渗透测试 | Kerberos协议及其部分攻击手法
        0day的产生 | 不懂代码的"代码审计"
        安装scrcpy-client模块av模块异常,环境问题解决方案
        leetcode hot100【LeetCode 279. 完全平方数】java实现
        OpenWrt下安装Mosquitto
        AnatoMask论文汇总
        【AI日记】24.11.01 LangChain、openai api和github copilot
      • 热门文章
      • 十款代码表白小特效 一个比一个浪漫 赶紧收藏起来吧!!!
        奉劝各位学弟学妹们,该打造你的技术影响力了!
        五年了,我在 CSDN 的两个一百万。
        Java俄罗斯方块,老程序员花了一个周末,连接中学年代!
        面试官都震惊,你这网络基础可以啊!
        你真的会用百度吗?我不信 — 那些不为人知的搜索引擎语法
        心情不好的时候,用 Python 画棵樱花树送给自己吧
        通宵一晚做出来的一款类似CS的第一人称射击游戏Demo!原来做游戏也不是很难,连憨憨学妹都学会了!
        13 万字 C 语言从入门到精通保姆级教程2021 年版
        10行代码集2000张美女图,Python爬虫120例,再上征途
      Copyright © 2022 侵权请联系2656653265@qq.com    京ICP备2022015340号-1
      正则表达式工具 cron表达式工具 密码生成工具

      京公网安备 11010502049817号