网关登录校验(2)----网关如何将用户信息传递给微服务

news2024/11/15 19:38:54

1.微服务获取用户信息

现在,网关已经可以完成登录校验并获取登录用户身份信息。但是当网关将请求转发到微服务时,微服务又该如何获取用户身份呢?

由于网关发送请求到微服务依然采用的是Http请求,因此我们可以将用户信息以请求头的方式传递到下游微服务。然后微服务可以从请求头中获取登录用户信息。考虑到微服务内部可能很多地方都需要用到登录用户信息,因此我们可以利用SpringMVC的拦截器来实现登录用户信息获取,并存入ThreadLocal,方便后续使用。

据图流程图如下:

因此,接下来我们要做的事情有:

  • 改造网关过滤器,在获取用户信息后保存到请求头,转发到下游微服务

  • 编写微服务拦截器,拦截请求获取用户信息,保存到ThreadLocal后放行

1.1.保存用户到请求头

首先,我们修改登录校验拦截器的处理逻辑,保存用户信息到请求头中:

package com.hmall.gateway.filters;

import com.hmall.common.exception.UnauthorizedException;
import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;


@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {

    private final AuthProperties authProperties;
    private final JwtTool jwtTool;
    private final AntPathMatcher antPathMatcher = new AntPathMatcher();

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        //1.获取到request
        ServerHttpRequest request = exchange.getRequest();
        //2.判断是否需要拦截
        String path = request.getPath().toString();
        if(isExcluded(path)){
            //如果不需要拦截,放行
            return chain.filter(exchange);
        }
        //3.从请求头获取到token
        List<String> headers = request.getHeaders().get("authorization");
        String token = null;
        if(headers != null && !headers.isEmpty()){
            token = headers.get(0);
        }
        //4.解析token,获取到用户id
        Long userId = null;
        try {
            userId = jwtTool.parseToken(token);
        } catch (UnauthorizedException e) {
            //token有问题,拦截
            ServerHttpResponse response = exchange.getResponse();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);//设置401未登录状态码
            return response.setComplete();//直接结束
        }
        //5.TODO 传递用户信息到微服务
        String userInfo = userId.toString();
        ServerWebExchange swe = exchange.mutate().request(builder -> builder.header("user-info",userInfo)).build();
        //6.放行
        return chain.filter(swe);
    }

    private boolean isExcluded(String path) {
        //匹配,如果成功匹配则true
        for (String pathPattern : authProperties.getExcludePaths()) {
            if (antPathMatcher.match(pathPattern, path)){
                return true;
            }
        }
        return false;
    }

    @Override
    public int getOrder() {
        return 0;
    }
}

1.2.拦截器获取用户信息

在hm-common中已经有一个用于保存登录用户的ThreadLocal工具:

接下来,我们只需要编写拦截器,获取用户信息并保存到UserContext,然后放行即可。

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

我们在hm-common模块下定义一个拦截器:

package com.hmall.common.interceptor;

import cn.hutool.core.util.StrUtil;
import com.hmall.common.utils.UserContext;
import org.springframework.web.servlet.HandlerInterceptor;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class UserInfoInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        //此拦截器不作拦截,而是微服务想获取到网关或者上游微服务传递的请求头(用户信息)
        //1.获取到请求头(用户信息)
        String header = request.getHeader("user-info");
        //2.判断是否为空,有则获取,存入ThreadLocal
        if(StrUtil.isNotBlank(header)){
            UserContext.setUser(Long.valueOf(header));
        }
        //3.放行
        return true;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        UserContext.removeUser();
    }
}

接着在hm-common模块下编写SpringMVC的配置类,配置登录拦截器:

package com.hmall.common.config;

import com.hmall.common.interceptors.UserInfoInterceptor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

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

不过,需要注意的是,这个配置类默认是不会生效的,因为它所在的包是com.hmall.common.config,与其它微服务的扫描包不一致,无法被扫描到,因此无法生效。

基于SpringBoot的自动装配原理,我们要将其添加到resources目录下的META-INF/spring.factories文件中:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.hmall.common.config.MyBatisConfig,\
  com.hmall.common.config.MvcConfig

1.3.恢复购物车代码

之前我们无法获取登录用户,所以把购物车服务的登录用户写死了,现在需要恢复到原来的样子。

找到cart-service模块的com.hmall.cart.service.impl.CartServiceImpl

 

 

 

 

 

 

 

 

 

 

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

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

相关文章

【数据结构】假设二叉树采用二叉链表存储,编写一棵二又树中序遍历的非递归算法。

编程题: 假设二叉树采用二叉链表存储,编写一棵二又树中序遍历的非递归算法。 分析: 算法描述: 非递归中序遍历二叉树的算法使用栈来辅助实现。首先,从根节点开始,沿着左子树不断向下, 将每个节点压入栈中。当到达最左端节点后,开始出栈并访问节点,接着转向右子树,重…

【Kubernetes知识点】HPA如何控制不同的资源实现自动扩缩容?

【Kubernetes知识点】HPA如何控制不同的资源实现自动扩缩容&#xff1f; 目录 1 概念 1.1 什么是HPA1.2 Deployment 与 HPA 的关系 1.2.1 工作原理 1.3 StatefulSet 与 HPA 的关系 1.3.1 工作原理 2 实验案例&#xff1a;HPA 控制 StatefulSet 进行扩缩容 2.1 部署一个有状态…

7--SpringBoot-后端开发、原理详解(面试高频提问点)

目录 SpringBoot原理 起步依赖 自动配置 配置优先级 Bean设置 获取Bean 第三方Bean SpringBoot原理 内容偏向于底层的原理分析 基于Spring框架进行项目的开发有两个不足的地方&#xff1a; 在pom.xml中依赖配置比较繁琐&#xff0c;在项目开发时&#xff0c;需要自己去找…

使用Anaconda安装pyTorch

1.Anaconda简介 Anaconda 是一个流行的 Python 数据科学和机器学习平台&#xff0c;它简化了包管理和部署&#xff0c;使得安装、运行和升级包及其依赖变得非常容易。Anaconda 通过其内置的 Conda 包和环境管理器&#xff0c;提供了一个强大的环境&#xff0c;用于科学计算&…

OpenAI GPT o1技术报告阅读(3)-英文阅读及理解

✨继续阅读报告&#xff1a;使用大模型来学习推理(Reason) 原文链接&#xff1a;https://openai.com/index/learning-to-reason-with-llms/ 这次我们继续看一个英文阅读理解的案例。 原问题&#xff1a; The following passage is the draft of an excerpt from a contempora…

springboot调用python脚本实现ocr图片文字识别功能

OCR简介: OCR(Optical Character Recognition),即光学字符识别,是一种利用计算机自动识别和解析图像中的文字信息的技术。它能够将纸质文档、图片、照片等载体上的文字信息转化为计算机可编辑和处理的文本数据。 一,准备工作 1,java环境 2,springboot项目 3,python环境 …

【二级C语言考试】自定义数据类型

C语言二级考试——自定义数据类型 十、结构体&#xff08;即“结构”&#xff09;与共同体&#xff08;即“联合”&#xff09; 用 typedef说明一个新类型。结构体和共用体类型数据的定义和成员的引用。通过结构体构成链表&#xff0c;单向链表的建立&#xff0c;结点数据的输出…

Java中ArrayList和LinkedList的比较

注&#xff1a;Joshua Bloch 就是 LinkedList 的作者 在Java中&#xff0c;ArrayList和LinkedList都是常用的列表实现类&#xff0c;它们都实现了List接口&#xff0c;但在内部工作原理和性能方面有显著差异。 ArrayList&#xff1a;基于动态数组实现。随着元素的增加&#x…

小新-13 2019 Intel款IML版【81UQ】原装出厂Win10系统镜像下载

恢复lenovo联想开箱状态&#xff0c;自带预装OEM系统安装包 链接&#xff1a;https://pan.baidu.com/s/1wwPriBoIwNOAfL-YcX1F7g?pwdg7ki 提取码&#xff1a;g7ki 联想原装出厂系统自带所有驱动、出厂主题壁纸、系统属性联机支持标志、系统属性专属LOGO标志、Office办公软…

如何联系真正的开发者而非公司??

&#x1f3c6;本文收录于《全栈Bug调优(实战版)》专栏&#xff0c;主要记录项目实战过程中所遇到的Bug或因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&am…

T9-猫狗识别2(暂时版qaq)

T9周&#xff1a;猫狗识别2 **一、前期工作**1.设置GPU,导入库2.导入数据3.查看数据 **二、数据预处理**1.加载数据2.可视化数据3.配置数据集 **三、构建CNN网络模型****四、编译模型****五、训练模型****六、模型评估****七、预测**八、总结&#xff08;暂时&#xff09; &…

信奥初赛解析:1-3-计算机软件系统

知识要点 软件系统是计算机的灵魂。没有安装软件的计算机称为“裸机”&#xff0c;无法完成任何工作硬件为软件提供运行平台。软件和硬件相互关联,两者之间可以相互转化&#xff0c;互为补充 计算机软件系统按其功能可分为系统软件和应用软件两大类 一、系统软件 系统软件是指…

【Redis入门到精通三】Redis核心数据类型(List,Set)详解

目录 Redis数据类型 ​编辑 1.List类型 &#xff08;1&#xff09;常见命令 &#xff08;2&#xff09;内部编码 2.Set类型 &#xff08;1&#xff09;常见命令 &#xff08;2&#xff09;内部编码 Redis数据类型 查阅Redis官方文档可知&#xff0c;Redis提供给用户的核…

【2024/09/20更新】植物大战僵尸杂交版V2.5下载

植物大战僵尸杂交版V2.5 2.5版本更新公告&#xff1a; 增加新关卡– 益智模式–两面夹击模式关卡 挑战模式关卡 增加新铲子–骷髅铲子 --银币购买-挖掉植物触发亡语或召唤骷髅僵尸 增加新植物– 4张白卡植物-通过两面夹击获得 2张金卡植物和4张星卡植物 游戏调整– 调整…

Coggle数据科学 | 科大讯飞AI大赛:玉米雄穗识别挑战赛

本文来源公众号“Coggle数据科学”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;科大讯飞AI大赛&#xff1a;玉米雄穗识别挑战赛 赛题名称&#xff1a;玉米雄穗识别挑战赛 赛题类型&#xff1a;计算机视觉、物体检测 赛题任务&…

图的应用(关键路径)

基于你设计的带权有向无环图&#xff0c;写出所有合法的关键路径&#xff0c;并算出关键路径总长度 文字描述&#xff1a;关键路径总长度的现实意义是什么&#xff1f; 1.关键路径 总长度454316 2.现实意义 从源点到汇点的所有路径中&#xff0c;具有最大路径长度的路径称…

MySQL高阶1892-页面推荐2

目录 题目 准备数据 分析数据 总结 题目 您正在为一个社交媒体网站实施一个页面推荐系统。如果页面被user_id的 至少一个朋友喜欢 &#xff0c;而 不被user_id喜欢 &#xff0c;你的系统将 推荐 一个页面到user_id。 编写一个解决方案来查找针对每个用户的所有可能的 页面…

感知笔记3:平面和物体检测

识别平面表面&#xff1a;这项技能使机器人能够检测物体通常所在的位置&#xff0c;如桌子和架子。这是搜索物体的第一步。识别物体&#xff1a;一旦您知道在哪里寻找&#xff0c;就必须在场景中识别不同的物体&#xff0c;并根据机器人的位置&#xff08;坐标系&#xff09;定…

【STL】pair 与 map:基础、操作与应用

C 标准库中提供了许多用于处理数据结构的容器和工具。pair 和 map 是两个非常有用的工具&#xff0c;广泛应用于存储和处理关联数据。在本文中&#xff0c;我们将详细介绍 pair 与 map 的相关操作&#xff0c;并结合代码实例为读者提供清晰的理解。 pair&#xff1a;成对数据的…

基于SpringBoot+Vue的家政预约平台系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、SSM项目源码 系统展示 【2025最新】基于JavaSpringBootVueMySQL的…