springboot中在filter中用threadlocal存放用户身份信息

本文章主要描述通过springboot的filter类,在过滤器中设置jwt信息进行身份信息保存的方法
流程:请求->过滤器->解析请求的body信息->放入threadlocal中

定义filter:一个使用 Servlet 规范的过滤器(Filter),它通过 @WebFilter 注解注册为拦截所有匹配 /api 路径的 HTTP 请求。

@WebFilter(“/api”) 注解指定了过滤器将应用于所有访问 /api路径的请求。
@Component 注解:

@Component 是 Spring 框架的注解,表明 JwtFilter 是一个 Spring 组件,可以被 Spring 容器管理,并支持依赖注入。
doFilter方法:
doFilter 方法定义了过滤器如何拦截和处理进入 Servlet 或 Servlet 容器的请求和响应。
方法签名:

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)throws IOException, ServletException;

这个方法接受三个参数:ServletRequest request、ServletResponse response 和 FilterChain chain。
它可能抛出 IOException 或 ServletException。
请求和响应:

doFilter 方法的前两个参数代表当前的请求和响应对象,你可以在这个方法中读取请求数据、修改请求和响应。
通常,在 doFilter 方法的最后,你需要调用 chain.doFilter(request, response) 来继续执行过滤器链中的下一个过滤器或目标资源。

如果要重新修改请求内容,可以用HttpServletRequestWrapper,HttpServletRequestWrapper 是一个包装器类,它扩展了 HttpServletRequest 接口,允许你修改或扩展请求的处理。使用 HttpServletRequestUriWrapper(这可能是一个自定义的包装器类,继承自 HttpServletRequestWrapper)的目的通常包括:

修改请求 URI:

你可能想要修改请求的 URI,但不想改变原始的 HttpServletRequest 对象。通过使用 HttpServletRequestUriWrapper,你可以包装原始请求并提供一个修改后的 URI。
保持原始请求不变:

使用包装器可以保持原始请求对象不变,同时允许你在过滤链中的某个点修改请求的某些方面。
过滤和预处理:

在调用 filterChain.doFilter 之前,你可以在 doFilter 方法中添加任何预处理逻辑,例如修改请求参数、更改请求路径、添加或修改请求头等。

import jakarta.servlet.Filter;
import jakarta.servlet.FilterChain;
import jakarta.servlet.FilterConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.annotation.WebFilter;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.MDC;@WebFilter("/api")
@Component
@Slf4j
public class JwtFilter implements Filter {@Overridepublic void init(FilterConfig filterConfig) {// noting to do}@Overridepublic void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)throws IOException, ServletException {var httpRequest = (HttpServletRequest) servletRequest;var requestBodyPayload = StreamUtils.copyToString(servletRequest.getInputStream(), StandardCharsets.UTF_8);// 解析Body参数,并存入threadLocal管理var jwtInfo = JwtUtil.getJwtInfoFromReq(requestBodyPayload);JwtUtil.setJwtInfo(jwtInfo);// 读取过body,需要重新设置bodyvar wrapper = new HttpServletRequestUriWrapper(httpRequest, httpRequest.getRequestURI(), requestBodyPayload);// 将请求传递到下一个过滤器(或者最终到达控制器方法)filterChain.doFilter(wrapper, servletResponse);}@Overridepublic void destroy() {JwtUtil.removeJwtInfo();MDC.clear();}
}

jwt信息:

@Slf4j
@Component
public class JwtUtil {/** 线程jwt信息维护 */private static final ThreadLocal<JwtInfo> REQUEST_BASE_INFO_THREAD_LOCAL = new ThreadLocal<>();/** 解析jwt信息 */public static JwtInfo getJwtInfoFromReq(String requestBodyPayload) {var jwtInfo = new JwtInfo();try {var requestBody = JsonUtil.getJsonNode(requestBodyPayload);log.info("[JwtUtil] RequestBody -> {}", requestBody);// 解析requestBody,转为jwtInfo对象jwtInfo.setRequestId(requestBody.get("RequestId") != null ? requestBody.get("RequestId").asText() : "");jwtInfo.setRegion(requestBody.get("Region") != null ? requestBody.get("Region").asText() : "");log.info("[JwtUtil] JwtInfo -> {}", jwtInfo);} catch (Exception e) {log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage(), e);}return jwtInfo;}/** 获取jwt信息 */public static JwtInfo getJwtInfo() {var jwtInfo = REQUEST_BASE_INFO_THREAD_LOCAL.get();if (Objects.isNull(jwtInfo)) {final var requestAttributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (Objects.nonNull(requestAttributes)) {var requestBodyPayload = "";try {requestBodyPayload = StreamUtils.copyToString(requestAttributes.getRequest().getInputStream(),StandardCharsets.UTF_8);} catch (Exception e) {log.error("[JwtUtil] Parse RequestBodyInfo Error, Error Message -> {}", e.getMessage());}jwtInfo = getJwtInfoFromReq(requestBodyPayload);setJwtInfo(jwtInfo);}}return jwtInfo;}/** 将jwt信息存入threadLocal中 */public static void setJwtInfo(JwtInfo jwtInfo) {REQUEST_BASE_INFO_THREAD_LOCAL.set(jwtInfo);// 将traceId写入日志变量MDC.put("traceId", jwtInfo.getRequestId());}public static void setJwtInfo(String appId, String ownerUin) {var jwtInfo = new JwtUtil.JwtInfo();jwtInfo.setRequestId(UUID.randomUUID().toString());setJwtInfo(jwtInfo);}/** 从threadLocal中删除jwt信息 */public static void removeJwtInfo() {REQUEST_BASE_INFO_THREAD_LOCAL.remove();}@Datapublic static class JwtInfo {@JsonPropertyDescription("请求requestId")private String requestId;@JsonPropertyDescription("请求的Region")private String region;}
}

获得jwt中的内容,去发送其他http请求:

   public static JsonNode sendHttpRequest(String method, String action, String url, Map<String, Object> body)throws IOException, InterruptedException {// 设置通用参数var jwtInfo = JwtUtil.getJwtInfo();if (jwtInfo != null) {body.put("RequestId", jwtInfo.getRequestId());body.put("AppId", Integer.valueOf(jwtInfo.getAppId()));body.put("Uin", jwtInfo.getUin());body.put("Region", jwtInfo.getRegion());}// 设置actionbody.put("Action", action);// 发送http请求,拿到请求结果HttpConnectUtil.ResponseInfo responseInfo = switch (method) {case "GET" -> HttpConnectUtil.sendGetByJson(url, JsonUtil.toJson(body));case "POST" -> HttpConnectUtil.sendPost(url, JsonUtil.toJson(body), new HashMap<>(2));default -> new HttpConnectUtil.ResponseInfo();};// 检查Api3格式返回结果,并解析var jsonResponse = JsonUtil.getJsonNode(responseInfo.getContent()).get("Response");var jsonError = jsonResponse.get("Error");if (jsonError != null) {var errorCode = jsonError.get("Code").asText();var errorMessage = jsonError.get("Message").asText();throw new ApiException(ErrorCode.INTERNAL_ERROR,String.format("错误码:[%s],错误信息:[%s]", errorCode, errorMessage));}return jsonResponse;}

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

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

相关文章

网络通信、BIO、NIO

1. 涉及的网络基础知识 Socket&#xff1a; 操作系统提供的api&#xff0c;介于应用层和tcp/ip层之间的软件层&#xff0c;封装服务器客户端之间网络通信相关内容&#xff0c;方便调用 IO多路复用&#xff1a; &#xff08;I/O Multiplexing&#xff09;是一种IO操作模式&a…

Android中线程的状态state都有哪些?S,R分表代表含义

在Android中&#xff0c;线程的状态&#xff08;state&#xff09;可以类比于Java线程的状态&#xff0c;因为Android是基于Java的。Java中线程的状态通常分为六种&#xff0c;这些状态在Android中也是适用的。具体状态及含义如下&#xff1a; NEW&#xff08;新生&#xff09…

Python 的 metaclass

文章目录 先说结论1. metaclass 的作用2. 主要的执行过程 1. metaclass.__new__2. metaclass.__call__关于 metaclass.__init__ 3. metaclass.__prepare__4. 自动创建 __slots__ 属性4.1 metaclass 的接口类4.2 metaclass conflict 5. Class metaprogramming 先说结论 1. meta…

Java技术栈总结:JVM虚拟机篇

一、Java的四种引用类型 1、强引用 最常见的引用&#xff0c;类似Object obj new Object()、String str “hello”。如果一个对象具有强引用&#xff0c;垃圾回收器绝对不会回收它。即使抛出“OutOfMemoryError”错误&#xff0c;程序终止&#xff0c;也不会随意回收具有强引…

20240710 每日AI必读资讯

&#x1f916;微软&#xff1a;不会像 OpenAI 一样阻止中国访问 AI 模型 - OpenAI 将于周二&#xff08;7 月 9 日&#xff09;开始阻止中国用户访问其 API。 - 微软发言人表示&#xff1a;Azure OpenAI API服务在中国的提供方式没有变化。 - 公司仍然通过部署在中国以外地区…

亲测解决! Package pdftex.def Error: ‘eps-converted-to.pdf‘ not found

这个问题在小虎写论文的时候遇到&#xff0c;解决方法是将eps文件替换成pdf或者png。 环境 win11 MiKTeX 解决方法 将eps文件转换成pdf或者图片的格式&#xff0c;然后嵌入的时候改一下后缀就好了。 \begin{figure}[!t] \centering \includegraphics[width\columnwidth]{…

妙笔生词智能写歌词软件:创新助力还是艺术之殇?

在音乐创作日益普及和多样化的当下&#xff0c;各种辅助工具层出不穷&#xff0c;妙笔生词智能写歌词软件便是其中之一。那么&#xff0c;它到底表现如何呢&#xff1f; 妙笔生词智能写歌词软件&#xff08;veve522&#xff09;的突出优点在于其便捷性和高效性。对于那些灵感稍…

c/c++:牛客小白月赛93

比赛链接 A 生不逢七 题目描述(题目链接添加链接描述)&#xff1a; 睡前游戏中最简单又最好玩的游戏就是这个啦&#xff01; 该游戏规则为&#xff1a;多名玩家轮流报数&#xff0c;当要报的数字中含有 7 或者是 7 的倍数时&#xff08;例如 37&#xff0c;49&#xff09;&…

腾讯又一平台即将停止运营

随着腾讯公司业务和战略的调整&#xff0c;某些业务逐渐退出历史舞台&#xff0c;如“腾讯直播平台NOW”&#xff0c;以及“QQ签到”&#xff0c;“腾讯待办”&#xff0c;“企鹅FM音频平台”等&#xff0c;最近又有一则重磅消息&#xff0c;那就是“腾讯课堂”也即将停止运营。…

类似评论、省市区这种具有层次结构的数据表怎么设计?

业务功能模块 评论、回复模块省市区表 设置一个给每个数据设置一个parent_id 例如&#xff1a; 某个视频下a写了条评论&#xff0c;那a的parent_id就是0;b回复了a&#xff0c;那b的parent_id就是a的id;c回复了b&#xff0c;那c的parent_id就是b的id; 这样&#xff0c;所有评论…

光耦测试项目

CTR 电流传输比 --->输入电流/输出电流&#xff08;温度越高差值越小&#xff09; IOL 低电平输出电流 --->输出的电流 VOL 低电平输出电压 --->输出的电压 ITH 输入阈值电流 --->vcc给电压&#xff0c;输入给电流(缓慢升高)&#xff0c;输出设置电流/电压 IOH…

Mosh|初学者 SQL 教程

sql文件链接&#xff1a;链接: https://pan.baidu.com/s/1okjsgssdxMkfKf8FEos7DA?pwdf9a9 提取码: f9a9 在mysql workbench 导入 create_databases.sql 文件&#xff0c;下面是运行成功的界面 快捷方式&#xff1a;全部运行可以同时按下controlcommandenter &#xff0c;或者…

ceph存储

1 存储简介 存储的三种方式包括&#xff1a;块存储、文件存储、对象存储1。此外&#xff0c;还有内存存储、硬盘存储和闪存存储2。 内存存储&#xff1a;临时性数据存储方式&#xff0c;存储速度快&#xff0c;容量有限&#xff0c;通常用来存储正在使用的程序和数据。硬盘存…

配置管理新纪元:Eureka引领分布式服务配置潮流

配置管理新纪元&#xff1a;Eureka引领分布式服务配置潮流 引言 在微服务架构中&#xff0c;服务配置的管理是一项复杂而关键的任务。随着服务数量的增加&#xff0c;传统的集中式配置管理逐渐显得力不从心。Eureka&#xff0c;作为Netflix开源的服务发现框架&#xff0c;提供…

【通信协议】八、CDL(Caterpillar Data Link)协议解析

1、协议简介 CDL(Caterpillar Data Link)是caterpillar的通信协议&#xff0c;该品牌发动机ECM与各控制单元进行通信时&#xff0c;采用基于RS-485的物理层规范进行开发的CDL协议进行通信&#xff1b; 2、物理层 信号传输方式&#xff1a;差分信号&#xff08;通过两条线的电…

稀疏建模介绍,详解机器学习知识

目录 一、什么是机器学习&#xff1f;二、稀疏建模介绍三、Lasso回归简介四、Lasso超参数调整与模型选择 一、什么是机器学习&#xff1f; 机器学习是一种人工智能技术&#xff0c;它使计算机系统能够从数据中学习并做出预测或决策&#xff0c;而无需明确编程。它涉及到使用算…

集训 Day 2 模拟赛总结

复盘 7&#xff1a;30 开题 想到几天前被普及组难度模拟赛支配的恐惧&#xff0c;下意识觉得题目很难 先看 T1&#xff0c;好像不是很难&#xff0c;魔改 Kruskal 应该就行 看 T2 &#xff0c;感觉很神奇&#xff0c;看到多串匹配想到 AC 自动机&#xff0c;又想了想 NOIP …

328. 奇偶链表

https://leetcode.cn/problems/odd-even-linked-list/https://leetcode.cn/problems/odd-even-linked-list/ 解题思路&#xff1a; 把第一个和第二个节点分别作为奇数、偶数的头节点&#xff0c;当遇到奇节点&#xff0c;删除&#xff0c;并插入到奇数头节点后&#xff0c;这样…

PPI(每英寸像素数)、DPI(每英寸点数)和Pixel(像素)的区别和联系?

一、定义 PPI、DPI和Pixel是图像处理、打印和显示领域中常用的三个概念&#xff0c;它们之间既有区别又有联系。以下是对这三个概念进行分别讲解&#xff1a; 1. PPI&#xff08;Pixels Per Inch&#xff09;&#xff0d;即每英寸像素数&#xff0c;是图像分辨率的一种表示方…

解决Spring Boot应用中的内存优化问题

解决Spring Boot应用中的内存优化问题 大家好&#xff0c;我是微赚淘客系统3.0的小编&#xff0c;也是冬天不穿秋裤&#xff0c;天冷也要风度的程序猿&#xff01; 1. Spring Boot应用的内存管理 在开发和部署Spring Boot应用时&#xff0c;有效地管理内存是确保应用性能和稳…