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

server/2024/10/21 13:41:20/

微服务网关

  • 网关
    • 网关路由
      • 快速入门
      • 路由属性
    • 路由断言
    • 网关登录校验
      • 自定义过滤器
      • 实现登录校验
      • 网关传递用户
      • 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.ppmy.cn/server/38953.html

相关文章

Paddle 基于ANN(全连接神经网络)的GAN(生成对抗网络)实现

什么是GAN GAN是生成对抗网络&#xff0c;将会根据一个随机向量&#xff0c;实现数据的生成&#xff08;如生成手写数字、生成文本等&#xff09;。 GAN的训练过程中&#xff0c;需要有一个生成器G和一个鉴别器D. 生成器用于生成数据&#xff0c;鉴定器用于鉴定数据的准确性&…

Objective-C的对象复制与拷贝选项

对象复制与拷贝 文章目录 对象复制与拷贝copy与mutablecopycopy与mutablecopy的简介示例&#xff1a;不可变对象的复制可变对象的复制 NSCopying和NSMutableCopying协议深复刻和浅复刻浅拷贝&#xff08;Shallow Copy&#xff09;&#xff1a;深拷贝&#xff08;Deep Copy&…

vue3+vite+ts 自定义指令详解

directive-自定义指令&#xff08;属于破坏性更新&#xff09; Vue中有v-if,v-for,v-bind&#xff0c;v-show,v-model 等等一系列方便快捷的指令 今天一起来了解一下vue里提供的自定义指令 Vue3指令的钩子函数 created 元素初始化的时候 beforeMount 指令绑定到元素后调用 只调…

【C++】string类的使用②(容量接口Capacity || 元素获取Element access)

&#x1f525;个人主页&#xff1a; Forcible Bug Maker &#x1f525;专栏&#xff1a; STL || C 目录 前言&#x1f525;容量接口&#xff08;Capacity&#xff09;size和lengthcapacitymax_sizereserveresizeclearemptyshrink_to_fit &#x1f525;元素获取&#xff08;Ele…

jQuery-1.语法、选择器、节点操作

jQuery jQueryJavaScriptQuery&#xff0c;是一个JavaScript函数库&#xff0c;为编写JavaScript提供了更高效便捷的接口。 jQuery安装 去官网下载jQuery&#xff0c;1.x版本练习就够用 jQuery引用 <script src"lib/jquery-1.11.2.min.js"></script>…

刷题笔记 - 滑动窗口

文章目录 滑动窗口最长无重复子串最小覆盖子串串联所有单词的子串长度最小的子数组滑动窗口最大值字符串的排列最小区间 滑动窗口 所有题目来自leetcode的回答&#xff1a;https://leetcode.cn/problems/longest-substring-without-repeating-characters/solutions/3982/hua-d…

Baidu Comate智能编码助手:大学生的代码编写助手

Baidu Comate智能编码助手&#xff1a;大学生的代码编写助手 前言一、关于Baidu Comate智能编码助手1.1 Baidu Comate智能编码助手简介1.2 产品功能 二、安装使用&#xff08;本文以pycharm为例&#xff09;三、我的百度Comate之旅3.1智能推荐3.1.1 单行推荐3.1.2 多行推荐 3.2…

利用自动获客软件实现高效精准获客

在数字化时代的浪潮中&#xff0c;企业之间的竞争愈发激烈。客户资源的获取成为企业生存和发展的关键。传统的获客方式如广告投放、线下推广等不仅成本高昂&#xff0c;而且效率和准确性难以保证。随着科技的进步&#xff0c;自动获客软件应运而生&#xff0c;它以其独特的优势…