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

微服务网关

  • 网关
    • 网关路由
      • 快速入门
      • 路由属性
    • 路由断言
    • 网关登录校验
      • 自定义过滤器
      • 实现登录校验
      • 网关传递用户
      • 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: gatewaycloud:nacos:server-addr: 服务器地址:8848gateway: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{@Overridepublic Mono<void> filter(ServerWebExchange exchange,GatewayFilterChain chain){//利用exchange进行登录校验的逻辑编写//方向,将共享数据传递给下一个过滤器中return chain.filter(exchange);}@Overridepublic 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>{@Overridepublic GatewayFilter apply(Object config){return new GatewayFilter(new GatewayFilter(){@Overridepublic 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();@Overridepublic Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){//获取requestServerHttpRequest request= exchange.getRequest();//判断是否需要做登录校验(向注册,登录界面就不需要做登录校验)if(isExclude(request.getPath().toString())){//放行return chain.filter(exchange);}//获取tokenString token=null;List<String> headers=request.getHeaders().get("token");if(headers !=null && !headers.isEmply()){token=headers.get(0);}//利用jwt工具类校验tokentry{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;}@Overridepublic int getOrder(){return 0;}
}

网关传递用户

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

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

     @Overridepublic Mono<Void> filter(ServerWebExchange exchange,GatewayFilterChain chain){//获取requestServerHttpRequest request= exchange.getRequest();//判断是否需要做登录校验(向注册,登录界面就不需要做登录校验)if(isExclude(request.getPath().toString())){//放行return chain.filter(exchange);}//获取tokenString token=null;List<String> headers=request.getHeaders().get("token");if(headers !=null && !headers.isEmply()){token=headers.get(0);}//利用jwt工具类校验tokentry{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{@Overridepublic boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception{//获取登录信息String userInfo=request.getHeader("user-info");//判断是否获取了用户,如果有,存入ThreadLocalif(StrUtil.isNotBlank(userInfo)){//存入到ThreadLocal中}// 放行return true;}@Overridepublic 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{ @Overridepublic void addInterceptors(InterceptorRegistry registry){registry.addInterceptor(new UserInfoInterceptor());}
}

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

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

OpenFeign传递用户

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

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

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

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Redis__数据类型

文章目录 &#x1f60a; 作者&#xff1a;Lion J &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_69252724 &#x1f389; 主题&#xff1a;Redis__数据类型 ⏱️ 创作时间&#xff1a;2024年04月28日 ———————————————— 这里写目录标题 文…

大模型争霸的下一站:不仅是超越GPT-4,更是寻求模型之间的平衡应用

文 | 智能相对论 作者 | 沈浪 知名科学杂志《Nature》发表了一篇关于大模型规模参数大小争议的文章《In Al, is bigger always better?》——AI大模型&#xff0c;越大越好吗&#xff1f;随着大模型应用走向实践&#xff0c;这一问题不可避免地成为了当前AI行业发展的焦点与…

迅雷永久破解

链接&#xff1a;https://pan.baidu.com/s/1ZGb1ljTPPG3NFsI8ghhWbA?pwdok7s 下载后解压 以管理员身份运行绿化.bat&#xff0c;会自动生成快捷方式&#xff0c;如果没有可以在program中运行Thunder.exe

【python】条件语句与循环语句

目录 一.条件语句 1.定义 2.条件语句格式 &#xff08;1&#xff09;if &#xff08;2&#xff09;if-else &#xff08;3&#xff09;elif功能 &#xff08;4&#xff09;if嵌套使用 3.猜拳游戏 二.循环语句 1. while循环 2.while嵌套 3.for循环 4.break和conti…

AI图书推荐:AI在语言学习教育领域的应用和挑战

这本书《AI在语言学习教育领域的应用和挑战》&#xff08;AI in Language Teaching, Learning, and Assessment&#xff09;由Fang Pan编辑&#xff0c;出版于IGI Global&#xff0c;主要探讨了人工智能&#xff08;AI&#xff09;在语言教育领域的应用、挑战以及潜在的益处。 …

JS基础:JS语法规范详解(最全!)

你好&#xff0c;我是云桃桃。 一个希望帮助更多朋友快速入门 WEB 前端的程序媛。 云桃桃-大专生&#xff0c;一枚程序媛&#xff0c;感谢关注。回复 “前端基础题”&#xff0c;可免费获得前端基础 100 题汇总&#xff0c;回复 “前端基础路线”&#xff0c;可获取完整web基础…

C++:自增运算符(++)重载

自增运算符&#xff08;&#xff09;分为前置自增和后置自增&#xff0c;它们两者主要的区别是&#xff1a;返回的值不同&#xff0c;以及执行自增操作的顺序不同。 前置自增运算符 &#xff1a; 前置自增运算符首先将操作数加1&#xff0c;然后返回自增后的值。 这意味着如果…

CNN笔记详解

CNN(卷积神经网络) 计算机视觉&#xff0c;当你们听到这一概念的是否好奇计算机到底是怎样知道这个图片是什么的呢&#xff1f;为此提出了卷积神经网络&#xff0c;通过卷积神经网络&#xff0c;计算机就可以识别出图片中的特征&#xff0c;从而识别出图片中的物体。看到这里充…

盘一盘接口测试的那些痛点,你现在会解决了吗

前言 说到接口测试&#xff0c;想必大家一定不会陌生。接口测试就是测试系统组件间&#xff0c;接口对接是否顺畅的一种测试。包括测试数据能否交换、能否传递、能否正常控制管理过程&#xff0c;以及系统间的相互逻辑依赖关系&#xff0c;等等。 由于接口测试主要是检测系统…

2024网络安全面试问题宝典(4万字)

2024网络安全厂商面试问题宝典(4万字) 目录 评分标准网络基础问题 TCP建立连接要进行3次握手&#xff08;syn-syn&#xff0c;ack-ack&#xff09;&#xff0c;而断开连接要进行4次&#xff08;fin-ack-fin-ack&#xff09;TCP&#xff0c;UDP区别&#xff1a;安全常用的协议…

数据库基础--MySQL多表查询之联表查询

联表查询 定义&#xff1a;多张表联合在一起查询&#xff0c;例如学生信息与学生班级表、部门与员工表 创建两张表&#xff0c;主表与从表 CREATE TABLE TestMain(id INT Not NULL AUTO_INCREMENT,nameVARCHAR(10),introduction VARCHAR(255),PRIMARY KEY(id) ); CREATE TAB…

自动驾驶主流芯片及平台架构(二)特斯拉自动驾驶芯片平台介绍

早期 对外采购mobileye EyeQ3 芯片摄像头半集成方案&#xff0c;主要是为了满足快速量产需求&#xff0c;且受制于研发资金不足限制&#xff1b; 中期 采用高算力NVIDIA 芯片平台其他摄像头供应商的特斯拉内部集成方案&#xff0c;mobileye开发节奏无法紧跟特斯拉需求&#xff…

select,poll,epoll

在 Linux Socket 服务器短编程时&#xff0c;为了处理大量客户的连接请求&#xff0c;需要使用非阻塞I/O和复用&#xff0c;select&#xff0c;poll 和 epoll 是 Linux API 提供的I/O复用方式。 \selectpollepoll操作方式遍历遍历回调底层实现数组链表哈希表IO效率每次调用都进…

ROS 2边学边练(43)-- 利用GTest写一个基本测试(C++)

前言 在ROS&#xff08;Robot Operating System&#xff09;中&#xff0c;gtest&#xff08;Google Test&#xff09;是一个广泛使用的C测试框架&#xff0c;用于编写和执行单元测试。这些测试可以验证ROS节点、服务和消息等的正确性和性能。 如果我们需要在写的包中添加测试&…

kubectl_入门_service详解

Service 我们知道 Pod 的生命周期是有限的。可以用 ReplicaSet 和Deployment 来动态的创建和销毁 Pod&#xff0c;每个 Pod 都有自己的 IP 地址&#xff0c;但是如果 Pod 重建了的话那么他的 IP 很有可能也就变化了。 这就会带来一个问题&#xff1a;比如我们有一些后端的 Po…

Flink时间语义 | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

【基于MAX98357的Minimax(百度)长文本语音合成TTS 接入教程】

【基于MAX98357的Minimax&#xff08;百度&#xff09;长文本语音合成TTS 接入教程】 1. 前言2. 先决条件2.1 硬件准备2.2 软件准备2.3 接线 3. 核心代码3.1 驱动实现3.2 代码解析 4. 播放文本5. 结论 视频地址&#xff1a; SeeedXIAO ESP32S3 Sense【基于MAX98357的Minimax&am…

redis中的双写一致性问题

双写一致性问题 1.先删除缓存或者先修改数据库都可能出现脏数据。 2.删除两次缓存&#xff0c;可以在一定程度上降低脏数据的出现。 3.延时是因为数据库一般采用主从分离&#xff0c;读写分离。延迟一会是让主节点把数据同步到从节点。 1.读写锁保证数据的强一致性 因为一般放…

监视器和显示器的区别,普通硬盘和监控硬盘的区别

监视器与显示器的区别&#xff0c;你真的知道吗&#xff1f; 中小型视频监控系统中&#xff0c;显示系统是最能展现效果的一个重要环节&#xff0c;显示系统的优劣将直接影响视频监控系统的用户体验满意度。 中小型视频监控系统中&#xff0c;显示系统是最能展现效果的一个重要…

Linux字符设备驱动-详解与实操:驱动架构、设备树、Pinctrl子系统和GPIO子系统、platform、设备树下的platform

如何编写一个驱动程序&#xff1a; &#xff08;1&#xff09;确定主设备号 &#xff08;2&#xff09;定义自己的file_operations结构体&#xff1a; 包含对应的open(drv_open)/read(drv_read)等设备操作函数&#xff0c;需要到内核中去注册 &#xff08;3&#xff09;实现…