SpringCloudGateway — 网关登录校验

单体架构时我们只需要完成一次用户登录、身份校验,就可以在所有业务中获取到用户信息。而微服务拆分后,每个微服务都独立部署,不再共享数据。也就意味着每个微服务都需要做登录校验,这显然不可取。

1. 思路分析

既然网关是所有微服务的入口,一切请求都需要先经过网关。我们完全可以把登录校验的工作放到网关去做。

不过,这里存在几个问题:

(1)网关路由是配置的,请求转发是Gateway内部代码,我们如何在转发之前做登录校验?

        可以使用网关过滤器。

(2)网关校验JWT之后,如何将用户信息传递给微服务?

        由于网关发送请求到微服务依然采用的是Http请求,因此我们可以将用户信息以请求头的方式传递到下游微服务。然后微服务可以从请求头中获取登录用户信息。

(3)微服务之间也会相互调用,这种调用不经过网关,又该如何传递用户信息?

        在微服务发起调用时把用户信息存入请求头。

2. 登录校验过滤器

白名单的配置:

application.ymlapplication.properties 文件中配置不需要拦截的路径白名单。

gateway:ignoreUrls:- /auth/login- /auth/register- /public/**

在这个示例中,/auth/login/auth/register/public/** 等路径将不需要进行登录校验。

package com.cyt.gateway.filter;@Component // 声明为Spring容器中的一个Bean
@RequiredArgsConstructor // 生成构造方法,注入final成员变量
@EnableConfigurationProperties(AuthProperties.class) // 启用配置类AuthProperties的属性注入
public class AuthGlobalFilter implements GlobalFilter, Ordered {// 从配置文件中注入白名单路径列表,用于存放不需要JWT校验的路径@Value("${gateway.ignoreUrls}")private List<String> ignoreUrls;private final JwtTool jwtTool; // JWT工具类,用于解析和校验JWT@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {// 1. 获取Request对象,以访问请求的相关信息ServerHttpRequest request = exchange.getRequest();// 2. 判断请求路径是否在白名单中(无需JWT校验)if (isIgnoreUrl(request.getPath().toString())) {// 路径在白名单中,直接放行请求return chain.filter(exchange);}// 3. 获取请求头中的token(假设token放在"authorization"头部)String token = null;List<String> headers = request.getHeaders().get("authorization");if (!CollUtils.isEmpty(headers)) { // 如果请求头包含authorization字段token = headers.get(0); // 获取第一个token值}// 4. 使用jwtTool校验并解析tokenLong userId = null;try {userId = jwtTool.parseToken(token); // 解析并获取用户ID} catch (UnauthorizedException e) {// 如果token无效或解析失败,则返回401状态码并拦截请求ServerHttpResponse response = exchange.getResponse();response.setRawStatusCode(401);return response.setComplete(); // 返回空的响应结束处理}// TODO 5. 如果token有效,可在此处传递用户信息(如通过exchange.getAttributes())System.out.println("userId = " + userId); // 打印用户ID供调试// 6. 放行请求return chain.filter(exchange);}/*** 判断路径是否在白名单中** @param path 请求路径* @return 如果路径在白名单中返回true,否则返回false*/private boolean isIgnoreUrl(String path) {for (String ignoreUrl : ignoreUrls) {// 使用正则匹配白名单路径中的通配符 "**"if (path.matches(ignoreUrl.replace("**", ".*"))) {return true; // 路径匹配白名单中的某一项,返回true}}return false; // 没有匹配到任何白名单路径,返回false}@Overridepublic int getOrder() {return 0; // 设置过滤器优先级,值越小优先级越高}
}

3. 保存用户到请求头

5.6.部分代码可以参照下面修改:

// 5.传递用户信息
// 将解析出的用户ID转换为字符串,以便可以在请求头中传递
String userInfo = userId.toString();// 使用 exchange.mutate() 方法创建一个新的 ServerWebExchange 对象,
// 该对象将携带额外的请求头 "user-info",包含用户ID信息。
// .mutate() 方法用于复制当前请求并进行修改。
// 在这里,我们使用 request(builder -> builder.header(...)) 方式为请求添加一个新的头部。
ServerWebExchange modifiedExchange = exchange.mutate().request(builder -> builder.header("user-info", userInfo)) // 将 "user-info" 头设置为用户ID字符串.build(); // 完成新的 ServerWebExchange 对象的构建// 6.放行
// 使用修改后的 ServerWebExchange 对象继续执行过滤链。
// 这样,下游服务可以通过 "user-info" 请求头获取到用户ID信息。
return chain.filter(modifiedExchange);

4. OpenFeign传递用户

在微服务发起调用时把用户信息存入请求头。

如何才能让每一个由OpenFeign发起的请求自动携带登录用户信息呢?

这里要借助Feign中提供的一个拦截器接口:feign.RequestInterceptor

我们只需要实现这个接口,然后实现apply方法,利用RequestTemplate类来添加请求头,将用户信息保存到请求头中。

可以在OpenFeign的配置类中添加一个Bean:

@Bean
public RequestInterceptor userInfoRequestInterceptor(){// 定义一个 Feign 的 RequestInterceptor Bean,用于在请求发出前执行自定义拦截操作return new RequestInterceptor() {@Overridepublic void apply(RequestTemplate template) {// 获取当前登录用户的ID// UserContext 是一个上下文工具类,用于存储和获取当前线程的用户信息Long userId = UserContext.getUser();// 检查用户ID是否为 null,如果为 null 则表示用户未登录或无法获取用户信息if(userId == null) {// 如果用户ID为空,不做任何处理,直接返回,跳过拦截器逻辑return;}// 如果用户ID不为空,将用户ID作为请求头添加到 Feign 请求中// "user-info" 是请求头的键,下游微服务可以从该请求头中获取用户IDtemplate.header("user-info", userId.toString());}};
}

5. 总结

思路分析中提到的三个问题,目前已经全部解决。

接下来,微服务需要用户信息,只需要编写拦截器,获取用户信息并保存到ThreadLocal中,然后放行即可。

由于每个微服务都有获取登录用户的需求,因此拦截器可以直接写在common公共服务中,并写好自动装配。这样微服务只需要引入common就可以直接具备拦截器功能,无需重复编写。

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

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

相关文章

vue3如何使用pinia设置全局状态,附常见面试题

1. stores/index.ts 文件 在 index.ts 中创建 store 实例并封装了注册逻辑&#xff0c;这样可以方便地将整个 Pinia 实例注册到 Vue 应用中。代码如下&#xff1a; import type { App } from vue import { createPinia } from piniaconst store createPinia()// 全局注册 st…

【微知】Nvida Mellanox网卡中速率SDR、DDR、QDR、FDR、EDR、HDR、NDR全称与速率?

文章目录 综述背景全称早期速率&#xff1a;中期当前 其他 综述 Single Data Rate (SDR) 10Gbps Double Data Rate (DDR) 20Gbps Quad Data Rate (QDR) 40Gbps Fourteen Data Rate (FDR) 56Gbps Enhanced Data Rate (EDR) 100Gbps High Data Rate (HDR) 200Gbps Next Data Rat…

融合虚拟化与容器技术,打造灵活又安全的AI算力服务

随着人工智能技术的不断进步&#xff0c;AI企业在迅速推进大模型业务时&#xff0c;往往会倾向于采用容器化的轻量部署方案。相较于传统的虚拟机部署&#xff0c;容器化在快速部署、资源利用、环境一致性和自动化编排等方面具备显著优势。 然而&#xff0c;容器技术所固有的隔…

Hunyuan-Large:推动AI技术进步的下一代语言模型

腾讯近期推出了基于Transformer架构的混合专家&#xff08;MoE&#xff09;模型——Hunyuan-Large&#xff08;Hunyuan-MoE-A52B&#xff09;。该模型目前是业界开源的最大MoE模型之一&#xff0c;拥有3890亿总参数和520亿激活参数&#xff0c;展示了极强的计算能力和资源优化优…

岛屿数量 广搜版BFS C#

和之前的卡码网深搜版是一道题 力扣第200题 99. 岛屿数量 题目描述 给定一个由 1&#xff08;陆地&#xff09;和 0&#xff08;水&#xff09;组成的矩阵&#xff0c;你需要计算岛屿的数量。岛屿由水平方向或垂直方向上相邻的陆地连接而成&#xff0c;并且四周都是水域。…

本地使用conda创建django虚拟环境

1、首先本地安装好conda。 2、创建django的虚拟环境 conda create -n django # 这里的 django只是虚拟的名称&#xff0c;自己随便名字就行&#xff0c;只要你自己知道这个是django的虚拟环境就行。 3、安装成功&#xff0c;查看虚拟环境 conda env list 4、激活虚拟环境…

rabbitMQ

官网&#xff1a;https://www.rabbitmq.com/ 一 介绍与安装 1 安装 我们同样基于Docker来安装RabbitMQ&#xff0c;使用下面的命令即可&#xff1a; docker run \-e RABBITMQ_DEFAULT_USERitheima \-e RABBITMQ_DEFAULT_PASS123321 \-v mq-plugins:/plugins \--name rabbi…

reg注册表研究与物理Hack

reg注册表研究与物理Hack 声明&#xff1a;内容的只是方便各位师傅学习知识&#xff0c;以下网站只涉及学习内容&#xff0c;其他的都与本人无关&#xff0c;切莫逾越法律红线&#xff0c;否则后果自负。 目录 reg注册表研究与物理HackWindows注册表修改注册表实现应用程序开机…

【黑盒测试】等价类划分法及实例

本文主要介绍黑盒测试之等价类划分法&#xff0c;如什么是等价类划分法&#xff0c;以及如何划分&#xff0c;设计等价类表。以及关于三角形案例的等价类划分法。 文章目录 一、什么是等价类划分法 二、划分等价类和列出等价类表 三、确定等价类的原则 四、建立等价类表 …

适用于个人或团队的文档管理和知识库系统,NAS快速部署『BookStack』

适用于个人或团队的文档管理和知识库系统&#xff0c;NAS快速部署『BookStack』 哈喽小伙伴们好&#xff0c;我是Stark-C~ 知识库对于很多需要和文字打交道的个人或者团队都不陌生对吧&#xff1f;对于我们个人来说&#xff0c;它可以将常用的学习资料、工作笔记、项目计划和…

delphi fmx android 自动更新(一)

12.2 android10测试通过 一,安卓权限设置 1,REQUEST_INSTALL_PACKAGES 权限 2,INTERNET 权限 3,READ_EXTERNAL_STORAGE 权限 4,WRITE_EXTERNAL_STORAGE 权限 5,READ_PHONE_STATE 二,安卓下载过程 一般是从http下载安装包 apk 所以,如果是http 则,manife…

《JVM第7课》堆区

文章目录 1.概念2.指定堆大小3.新生代和老年代3.1 新生代3.2 老年代3.3 动画演示 4.分代收集理念 1.概念 堆是JVM中最重要的一块区域&#xff0c;JVM规范中规定所有的对象和数组都应该存放在堆中&#xff0c;在执行字节码指令时&#xff0c;会把创建的对象存入堆中&#xff0c…

【笔记】自动驾驶预测与决策规划_Part6_不确定性感知的决策过程

文章目录 0. 前言1. 部分观测的马尔可夫决策过程1.1 POMDP的思想以及与MDP的联系1.1.1 MDP的过程回顾1.1.2 POMDP定义1.1.3 与MDP的联系及区别POMDP 视角MDP 视角决策次数对最优解的影响 1.2 POMDP的3种常规解法1.2.1 连续状态的“Belief MDP”方法1. 信念状态的定义2. Belief …

Spring Boot框架下的知识管理与多维分类

4 系统设计 系统分析接下来的操作步骤就是系统的设计&#xff0c;这部分内容也是不能马虎对待的。因为生活都是在不断产生变化&#xff0c;人们需求也是在不断改变&#xff0c;开发技术也是在不断升级&#xff0c;所以程序也需要考虑在今后可以方便进行功能扩展&#xff0c;完成…

LeetCode17. 电话号码的字母组合(2024秋季每日一题 59)

给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;digits “23” 输出&#xff1a;[“…

Nature Methods | 基于流形约束的RNA速度推断精准解析细胞周期动态调节规律

生信碱移 VeloCycle算法 VeloCycle&#xff1a;基于流形约束的RNA速度推断在细胞周期动态中的精准解析 今天给各位老铁们分享一篇于2024年10月31号发表在 Nature Methods [IF: 36.1] 的文章&#xff1a;"Statistical inference with a manifold-constrained RNA velocity…

Spring挖掘:(AOP篇)

学习AOP时,我们首先来了解一下何为AOP 一. 概念 AOP&#xff08;面向切面编程&#xff0c;Aspect Oriented Programming&#xff09;是一种编程技术&#xff0c;旨在通过预编译方式或运行期动态代理实现程序功能的统一管理和增强。AOP的主要目标是在不改变原有业务逻辑代码的…

【机器学习】k最近邻分类

&#x1f4dd;本文介绍 本文为作者阅读鸢尾花书籍以及一些其他资料的k最近邻分类后&#xff0c;所作笔记 &#x1f44b;作者简介&#xff1a;一个正在积极探索的本科生 &#x1f4f1;联系方式&#xff1a;943641266(QQ) &#x1f6aa;Github地址&#xff1a;https://github.com…

《深度学习》bert自然语言处理框架

目录 一&#xff0c;关于bert框架 1、什么是bert 2、模型结构 自注意力机制&#xff1a; 3、预训练任务 4、双向性 5、微调&#xff08;Fine-tuning&#xff09; 6、表现与影响 二、Transformer 1、传统RNN网络计算时存在的问题 1&#xff09;串联 2&#xff09;并行…

开源 - Ideal库 - 常用时间转换扩展方法(一)

从事软件开发这么多年&#xff0c;平时也积累了一些方便自己快速开发的帮助类&#xff0c;一直在想着以什么方式分享出来&#xff0c;因此有了这个系列文章&#xff0c;后面我将以《开源-Ideal库》系列文章分享一些我认为比较成熟、比较方便、比较好的代码&#xff0c;如果感觉…