【微服务】网关(详细知识以及登录验证)

微服务网关

  • 网关
    • 网关路由
      • 快速入门
      • 路由属性
    • 路由断言
    • 网关登录校验
      • 自定义过滤器
      • 实现登录校验
      • 网关传递用户
      • OpenFeign传递用户

网关

网络的关口,负责请求的路由,转发,身份校验

当我们把一个单体项目分成多个微服务并部署在多台服务器中,这时由于地址的不同,可能出现身份校验,地址过多等问题

我们通过网关,将微服务集群统一在一个网关之下,并在通过注册中心将服务拉取到网关之中,自此我们直接访问网关,由网关进行对应微服务的路由转发和身份校验

在SpringCloud中网关的实现包括两种:
Spring Cloud Gateway:基于WebFlux响应式编程,无需调优即可获取优异性能
Netflix:基于Servlet的阻塞式编程,需要调优才能获取与SpringCloudGateway类似的性能

网关路由

快速入门

网关判断由哪个微服务进行处理的过程就是网关路由

  1. 引入依赖网关,Nacos,Loadbalancer
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-gateway</artifactId>
        </dependency>
        <dependency>
            <groupId>com.alibaba.cloud</groupId>
            <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-cloud-starter-loadbalancer</artifactId>
        </dependency>
  1. 创建一个新的网关微服务模块,并创建启动类
@SpringBootApplication
public class GatewayApplication{
      public static void main(String[] args){
      SpringApplication.run(GatewayApplication.Class,args);
      }
}
  1. 配置网关配置
server:
   port: 8080
spring:
   application:
      name: gateway
   cloud:
      nacos:
        server-addr: 服务器地址:8848
      gateway:
        routes:
          -id: 对应的服务名称
          uri: lb://服务名称  # lb意思是负载均衡
          predicates:
            - Path=/路径名称/**
          # 配置多个路由
          -id:

路由属性

网关路由对应的java类型是RouteDefinition,其中常见的属性:
id:路由的唯一标识
uri:路由的目标地址
predicates:路由断言,判断请求是否符合当前路由
filters:路由过滤器,对请求或响应做特殊处理

路由断言

Spring提供了12种基本的RoutePredicateFactory实现:
在这里插入图片描述
网关提供了很多的路由过滤器,每种过滤器都有独特的作用:
在这里插入图片描述
对应的过滤器可以在配置文件中进行配置

网关登录校验

在这里插入图片描述
此处为网关内部的处理逻辑,我们要进行登录校验的处理需要在过滤器的最前面添加一个自定义的过滤器,在pre阶段进行登录校验
校验成功之后,网关如何将信息传递给微服务:

将用户信息保存到请求头当中进行传递

微服务之间该如何传递校验信息:

也是保存信息到请求头当中,但是请求头的发送是由Openfeign来实现的

自定义过滤器

网关过滤器有两种:
GatewayFilter:路由过滤器,作用于任意指定的路由,默认不生效,要配置到路由后生效(在配置文件中进行配置)
GlobalFilter:全局过滤器,作用范围是所有路由,声明后自动生效(自定义之后在配置文件中使用)
我们这里通过GlobalFilter进行登录校验的实现

public interface GlobalFilter{
      Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain);
}

通过这个方法实现过滤器中的操作,第一个参数是请求上下文,包含整个过滤器链中的共享数据,比如request,response等等,第二个参数是过滤器链,当前过滤器执行完成之后,要调用过滤器中的下一个过滤器

网关采用非阻塞式的编程,Mono中编写一个回调函数,当过滤器将来执行到POST的时候调用回调函数,过滤器将不再进行长时间的等待

我们实现该接口实现过滤器:

@Component
public class MyGlobalFilter implements GlobalFilter,Ordered{
      @Override
      public Mono<void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
      //利用exchange进行登录校验的逻辑编写
      //方向,将共享数据传递给下一个过滤器中
      return chain.filter(exchange);
      }
      @Override
      public int getOrder(){
           return 0;
      }
}

注意:查看过滤器链,将鼠标放在GlobalFilter上按ctrl+H

实现Ordered接口,重写getOrder方法,返回的值越小,则过滤器在过滤器链中的优先级越高

自定义之后在配置文件中进行配置使用:

spring:
   cloud:
      gateway:
        default-filters:
        -AddRequestHeader=a,b

通常我们使用上述的自定义过滤器,但是还有一种过滤器GatewayFilter自定义过滤器,使用过滤器工厂AbstractGateWayFilterFactory:

@Component
public class GLQFilterFactory extends AbstractGatewayFilterFactory<Object>{
    @Override
    public GatewayFilter apply(Object config){
     return new GatewayFilter(new GatewayFilter(){
       @Override
       public Mono<void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
          //编写过滤器逻辑
          //放行
          return chain.filter(exchange);
       }
     }1);
    }
}

自定义过滤器类的类名的前缀就是将来的过滤器的名字,而后半部分应该是类名

实现登录校验

在这里插入图片描述

@Component
public class AuthGlobalFilter implements GlobalFilter,Ordered{
     //不用登录校验的地址实体类
     private final AuthProperties authproperties;
     private final JWtTool jwttool;
     //spring提供的匹配工具类
     private final AntPathMatcher antpathMatcher=new AntPathMatcher();
     @Override
     public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
       //获取request
       ServerHttpRequest request= exchange.getRequest();
       //判断是否需要做登录校验(向注册,登录界面就不需要做登录校验)
       if(isExclude(request.getPath().toString())){
       //放行
       return chain.filter(exchange);
       }
       //获取token
       String token=null;
       List<String> headers=request.getHeaders().get("token");
       if(headers !=null && !headers.isEmply()){
         token=headers.get(0);
       }
       //利用jwt工具类校验token
       try{
       Long userid=jwttool.parseToken(token);
         }catch (UnauthorizedException e){
             //拦截设置响应状态码为401(未登录)
             ServerHttpResponse response=exchange.getResponse();
             response.setStatusCode(HttpStatus.UNAUTHORIZED);
         }
         //放行
         return chain.filter(exchange);
     }
     private  boolean isExclude(String path){
      for(String pathPattern : authProperties.getExcludePaths()){
         if(antPathMatcher.match(pathPattern,path)){
           return true;
         }
      }
      return false;
     }
           @Override
      public int getOrder(){
           return 0;
      }
}

网关传递用户

前面所将的需要将信息传递给的微服务,需要将信息保存到请求头中,而在微服务中需要设置拦截器将所有用户信息保存到ThreadLocal中

如何向微服务中进行传递,需要略微修改上述所讲的过滤器:

     @Override
     public Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){
       //获取request
       ServerHttpRequest request= exchange.getRequest();
       //判断是否需要做登录校验(向注册,登录界面就不需要做登录校验)
       if(isExclude(request.getPath().toString())){
       //放行
       return chain.filter(exchange);
       }
       //获取token
       String token=null;
       List<String> headers=request.getHeaders().get("token");
       if(headers !=null && !headers.isEmply()){
         token=headers.get(0);
       }
       //利用jwt工具类校验token
       try{
       Long userid=jwttool.parseToken(token);
         }catch (UnauthorizedException e){
             //拦截设置响应状态码为401(未登录)
             ServerHttpResponse response=exchange.getResponse();
             response.setStatusCode(HttpStatus.UNAUTHORIZED);
         }
         //保存到请求头中,传递给微服务
         String userinfo=userid.toString();
         ServerWebExchange ww=exchange.mutate()
                            .request(builder->builder.header("user-info",userinfo))
                            .build();
         //放行
         return chain.filter(ww);
     }

将拦截器单独写在一个微服务当中,这样避免代码冗余:

public class UserInfoInterceptor implements	HandlerInterceptor{
     @Override
     public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception{
     //获取登录信息
     String userInfo=request.getHeader("user-info");
     //判断是否获取了用户,如果有,存入ThreadLocal
     if(StrUtil.isNotBlank(userInfo)){
         //存入到ThreadLocal中
     }
     // 放行
     return true;
     }
     @Override
     public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception{
     
     }
}

创建好之后在继承了WebMvcConfigurer的配置类中添加拦截器
这时别的微服务还是用不了拦截器,因为它配置类的包没有被扫到,这时我们需要将添加拦截器的配置类放到resources目录下的META-INF文件中添加配置类

@Configuration
@ConditionalOnClass(DispatcherServlet.class)
public class MvcConfig implements WebMvcConfigurer{ 
       @Override
       public void addInterceptors(InterceptorRegistry registry){
          registry.addInterceptor(new UserInfoInterceptor());
       }
}

注意:如果运行的时候网关模块报错

是因为网关的底层不是SpringMVC,而是响应式编程,而WebMvcConfigurer是MVC中提供的,所以我们在配置类上方添加注解,当有MVC的核心api就是DispatcherServlet,拥有这个的微服务该配置类生效

OpenFeign传递用户

微服务项目中的很多业务要被多个微服务共同合作完成,而这个过程中也需要传递登录用户信息
openFeign中提供了一个拦截器接口,所有有Openfeign发起的请求都会先调用拦截器处理请求

将此拦截器写在当时定义的Openfeign的微服务项目中,以便日后统一调用

public class Myconfig{
   @Bean
   public RequestInterceptor userinterceptor(){
      return new RequestInterceptor(){
         @Override
         public void apply(RequestTemplate template){
           //将添加请求头信息
           Long userid=Usercontext.getUser();
           if(userid!=null){
               template.header("user-info",userid.toString()) ;
           }
         }
      }
   }
}

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

DDR4 新功能介绍

DDR4(第四代双倍数据率同步动态随机存取内存)相较于其前代DDR3,引入了一些新的功能和改进,这些新功能有助于提高内存的性能、降低功耗以及增强系统的可靠性,包括VPP、DBI(Data Bus Inversion,数据总线翻转)和DMI(与LPDDR4相关)。以下是对这些功能的简要说明: 更高的…

java—异常

异常 什么是异常 异常的体系 编译时异常处理方式 1、选择报错的整个代码块&#xff0c;快捷键crtlaltt键&#xff0c;选择try/catch将代码围起来。 2、编译异常处理方式2 在main方法上抛出异常 自定义异常 例子&#xff1a; 自定义运行时异常 自定义编译时异常 异常…

视觉图像信息处理与FPGA实现第九次作业——直方图均衡

RAM的B站视频解析 RAM的文档 一、65536x8位的单端口RAM timescale 1ns / 1ps //SPRF Single Port Read/Write Function //65535 是RAM中总的字数&#xff0c;也就是存储深度&#xff0c;X8表示每个字是8位的 module SPRF65536X8(Q,CLK,CEN,WEN,A,D );//输出寄存器Qoutput [7…

如何在已经安装好的PostgreSQL14中安装uuid 扩展

当前环境 PG14.8 LINUX 8.8 存在问题&#xff1a; 开发人员问&#xff0c;PG中&#xff0c;支持 生成UUID吗&#xff0c;具体是什么&#xff0c;答&#xff0c;类似这个函数 uuid_generate_v4() 看了一下&#xff0c; select uuid_generate_v4();会报错&#xff0…

2024-05-07 商业分析-如何在社会层面做一个更好的工具人-记录

摘要: 2024-05-07 商业分析-如何成为一个靠谱的工具人 如何在社会层面做一个更好的工具人 那么今天讲的这个主题呢&#xff0c;对吧&#xff1f;你们一看啊&#xff0c;就觉得这个就不应该我讲是吧啊&#xff0c;但是呢这个逻辑呢我还得跟你们讲一下啊&#xff0c;就是如何成为…

2009-2022年上市公司华证ESG评级评分数据(含细分项)

2009-2022年上市公司华证ESG评级评分数据&#xff08;含细分项&#xff09; 1、时间&#xff1a;2009-2022年 2、来源&#xff1a;华证ESG 3、指标&#xff1a;证券代码、证券简称、综合评级、年度、综合得分、E评级、E得分、S评级、S得分、G评级、G得分 4、范围&#xff1…

AI伦理和安全风险管理终极指南

人工智能&#xff08;AI&#xff09;正在迅速改变各个领域的软件开发和部署。驱动这一转变的两个关键群体为人工智能开发者和人工智能集成商。开发人员处于创建基础人工智能技术的最前沿&#xff0c;包括生成式人工智能&#xff08;GenAI&#xff09;模型、自然语言处理&#x…

Python读取ASC文件并转换成Excel文件(坐标)

import pandas as pd# 读取asc文件&#xff0c;指定空格为分隔符 df pd.read_csv(out_view2.asc, sep , headerNone)# 去掉空列 df df.dropna(howall, axis1)# 将数据保存到Excel文件 df.to_excel(out_view2.xlsx, indexFalse, headerFalse)效果图

Day1| Java基础 | 1 面向对象特性

Day1 | Java基础 | 1 面向对象特性 基础补充版Java中的开闭原则面向对象继承实现继承this和super关键字修饰符Object类和转型子父类初始化顺序 多态一个简单应用在构造方法中调用多态方法多态与向下转型 问题回答版面向对象面向对象的三大特性是什么&#xff1f;多态特性你是怎…

unity华为sdk接入指路指南

目前比较靠谱的几个方案&#xff1a;试过几个仅供参考 温馨提示&#xff1a;最高目前可支持方案到unity2021版本以下&#xff0c;以上请联系华为官方寻求技术支持 Unity集成华为游戏服务SDK方式&#xff08;一&#xff09;&#xff1a;集成Unity官方游戏SDK&#xff1a; 华为…

代码随想录算法训练营第十八天:二叉树的层序遍历(中间放假)

代码随想录算法训练营第十八天&#xff1a;二叉树的层序遍历&#xff08;中间放假&#xff09; ‍ ​​ 102.二叉树的层序遍历 力扣题目链接(opens new window) 给你一个二叉树&#xff0c;请你返回其按 层序遍历 得到的节点值。 &#xff08;即逐层地&#xff0c;从左到右…

速览Coinbase 2024Q1 财报重点:业务全面开花,净利润达11.8亿美元

作者&#xff1a;范佳宝&#xff0c;Odaily 星球日报 近期&#xff0c;Coinbase 发布了其 2024 年第一季度财报。 报告显示&#xff0c;Coinbase 第一季度营收为 16.4 亿美元&#xff0c;高于分析师平均预期的 13.4 亿美元&#xff1b;净利润为 11.8 亿美元&#xff0c;合每股…

关于Centos 7/8 网络设置 与工具连接

网络三步曲的配置 1、首先更改虚拟机的网络配置 查看子网地址以及网关 如果有要求需要更改IP地址&#xff0c;规定第三位是指定数值&#xff0c;那么需要全部更改 例如&#xff0c;IP地址为192.168.200.30 其中200为重点&#xff0c;更改时为以下步骤 1、点击DHCP设置&#x…

贪吃蛇大作战(C语言--实战项目)

朋友们&#xff01;好久不见。经过一段时间的沉淀&#xff0c;我这篇文章来和大家分享贪吃蛇大作战这个游戏是怎么实现的。 &#xff08;一&#xff09;.贪吃蛇背景了解及效果展示 首先相信贪吃蛇游戏绝对称的上是我们00后的童年&#xff0c;不仅是贪吃蛇还有俄罗斯⽅块&…

找不到模块“vue-router”。你的意思是要将 moduleResolution 选项设置为 node,还是要将别名添加到 paths 选项中?

在tsconfig.app.json中添加&#xff0c;记得一定是 tsconfig.app.json 中&#xff0c;如添加到 tsconfig.node.json 还是会报错的 哈哈哈哈&#xff0c;不瞒你们&#xff0c;我就添加错了&#xff0c;哈哈哈。所以这也算写一个demo提醒自己 "compilerOptions": {&qu…

【牛客】排列计算

原题链接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 如果直接涂色来计算单点权重&#xff0c;2e5*2e5必然超时。 所以用差分进行优化。 3. 代码实现 #include<bits/stdc.h> using name…

Go语言fmt包深度探索:格式化输入输出的利器

&#x1f525; 个人主页&#xff1a;空白诗 文章目录 &#x1f3ad; 引言一、基础输出函数fmt.Print与fmt.Println&#x1f4cc; fmt.Print&#xff1a;纯粹输出&#xff0c;不带换行&#x1f4cc; fmt.Println&#xff1a;输出后自动添加换行符 二、格式化输出fmt.Printf&…

鸿蒙开发接口Ability框架:【@ohos.application.missionManager (missionManager)】

missionManager missionManager模块提供系统任务管理能力&#xff0c;包括对系统任务执行锁定、解锁、清理、切换到前台等操作。 说明&#xff1a; 本模块首批接口从API version 8开始支持。后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 导入模块 impo…

“Postman 中文版使用教程:如何切换到中文界面?”

Postman 的很好用的接口测试软件。但是&#xff0c;Postman 默认是英文版的&#xff0c;也不支持在软件内切换为中文版。很多同学的英语并不是很好&#xff0c;看到一堆的英文很是头痛。 今天我们来介绍下&#xff1a;切换到 Postman 中文版的方法。想要学习更多的关于 Postma…

Type-C转音频(USB2.0数据传输)+PD充电芯片乐得瑞LDR6500/LDR6023

LDR6500 USB-C DRP 接口 USB PD 通信芯片概述 Type-C转音频(USB2.0数据传输)PD充电芯片乐得瑞LDR6500LDR6500是乐得瑞科技针对USB Type-C标准中的Bridge设备而开发的USB-C DRP&#xff08;Dual Role Port&#xff0c;双角色端口&#xff09;接口USB PD&#xff08;Power Deliv…