news 2026/7/24 23:15:11

微服务框架中获取用户信息

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
微服务框架中获取用户信息

从流程可以看出,浏览在访问服务时会携带jwt向微服务发起请求,中间会先经过网关。网关从jwt中获取用户信息并保存到请求中,然后再转发给对应服务。在到达业务层之前会有拦截器将用户信息存入ThreadLocal中。

1.在经过网关过滤器被拦截时将用户信息保存到请求头中

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取request ServerHttpRequest request = exchange.getRequest(); // 判断是否需要拦截 if(isExclude(request.getPath().toString())){ // 无需拦截 放行 return chain.filter(exchange); } // 获取请求头中的token String token = null; List<String> headers = request.getHeaders().get("authorization"); if(CollUtils.isNotEmpty(headers)){ token = headers.get(0); } //校验并解析token Long userId = null; try { userId = jwtTool.parseToken(token); } catch (UnauthorizedException e) { //无效 拦截 ServerHttpResponse response = exchange.getResponse(); response.setRawStatusCode(401); return response.setComplete(); } // 如果有效,传递用户信息 String userInfo = userId.toString(); ServerWebExchange ex = exchange.mutate() .request(b -> b.header("user-info", userInfo)) .build(); // 放行 return chain.filter(exchange); }

由于jwt令牌中会携带用户id,将用户id存入请求头"user-info"中;

2.在公用模块中定义拦截器,在拦截器中将请求头中用户信息保存到ThreadLocal中

public class UserInfoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userInfo = request.getHeader("user-info"); //保存到ThreadLocal if(StrUtil.isNotBlank(userInfo)){ UserContext.setUser(Long.valueOf(userInfo)); } //放行 return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //移除用户 UserContext.removeUser(); } }

"user-info"请求头中获取到用户id,将其保存到ThreadLocal中。在经过网关后会先经过该拦截器再到达业务层,从而携带登录用户的id到业务逻辑中。

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

在该模块中定义SpringMVC的配置类,将定义的拦截器注册

由于是在微服务框架中,在其他启动模块中不会扫描到MvcConfig,所以需要手动配置

3.处理跨服务调用无法拿到用户信息的问题

当基于OpenFeign实现跨服务调用时,从一个服务向另一个服务发送请求时Feign会重新创建一个Http请求,而这个新的请求并不会继承原始的请求头信息。所以需要实现Feign提供的一个拦截器接口:feign.RequestInterceptor

public class DefaultFeignConfig { @Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor(){ @Override public void apply(RequestTemplate requestTemplate) { //获取登录用户 Long userId = UserContext.getUser(); if(userId == null){ return; } //如果不为空,添加到请求头中 requestTemplate.header("user-info", userId.toString()); } }; } }

在Feign发送Http请求前,通过RequestInterceptor拦截器将请求头添加到Feign创建的请求的头信息中。
Pasted image 20260724174630.png由于这是Feign的最佳实践,如果在DefaultFeignConfig类中加了 @Configuration,Spring 组件扫描会把它扫进主容器,里面的 @Bean 就变成全局 Bean 了。而 Feign 的配置类应该只作用于 Feign 自身的上下文,避免污染主容器。所以 Feign 框架会自己拿到这个类,为它创建独立的子上下文,完全不需要 Spring 扫描。需要在每个需要用到的微服务模块中添加这个注解。从流程可以看出,浏览在访问服务时会携带jwt向微服务发起请求,中间会先经过网关。网关从jwt中获取用户信息并保存到请求中,然后再转发给对应服务。在到达业务层之前会有拦截器将用户信息存入ThreadLocal中。

1.在经过网关过滤器被拦截时将用户信息保存到请求头中

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取request ServerHttpRequest request = exchange.getRequest(); // 判断是否需要拦截 if(isExclude(request.getPath().toString())){ // 无需拦截 放行 return chain.filter(exchange); } // 获取请求头中的token String token = null; List<String> headers = request.getHeaders().get("authorization"); if(CollUtils.isNotEmpty(headers)){ token = headers.get(0); } //校验并解析token Long userId = null; try { userId = jwtTool.parseToken(token); } catch (UnauthorizedException e) { //无效 拦截 ServerHttpResponse response = exchange.getResponse(); response.setRawStatusCode(401); return response.setComplete(); } // 如果有效,传递用户信息 String userInfo = userId.toString(); ServerWebExchange ex = exchange.mutate() .request(b -> b.header("user-info", userInfo)) .build(); // 放行 return chain.filter(exchange); }

由于jwt令牌中会携带用户id,将用户id存入请求头*"user-info"*中;

2.在公用模块中定义拦截器,在拦截器中将请求头中用户信息保存到ThreadLocal中

public class UserInfoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userInfo = request.getHeader("user-info"); //保存到ThreadLocal if(StrUtil.isNotBlank(userInfo)){ UserContext.setUser(Long.valueOf(userInfo)); } //放行 return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //移除用户 UserContext.removeUser(); } }

从*"user-info"*请求头中获取到用户id,将其保存到ThreadLocal中。在经过网关后会先经过该拦截器再到达业务层,从而携带登录用户的id到业务逻辑中。

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

在该模块中定义SpringMVC的配置类,将定义的拦截器注册

697由于是在微服务框架中,在其他启动模块中不会扫描到MvcConfig,所以需要手动配置

3.处理跨服务调用无法拿到用户信息的问题

当基于OpenFeign实现跨服务调用时,从一个服务向另一个服务发送请求时Feign会重新创建一个Http请求,而这个新的请求并不会继承原始的请求头信息。所以需要实现Feign提供的一个拦截器接口:feign.RequestInterceptor

public class DefaultFeignConfig { @Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor(){ @Override public void apply(RequestTemplate requestTemplate) { //获取登录用户 Long userId = UserContext.getUser(); if(userId == null){ return; } //如果不为空,添加到请求头中 requestTemplate.header("user-info", userId.toString()); } }; } }

在Feign发送Http请求前,通过RequestInterceptor拦截器将请求头添加到Feign创建的请求的头信息中。
Pasted image 20260724174630.png由于这是Feign的最佳实践,如果在DefaultFeignConfig类中加了 @Configuration,Spring 组件扫描会把它扫进主容器,里面的 @Bean 就变成全局 Bean 了。而 Feign 的配置类应该只作用于 Feign 自身的上下文,避免污染主容器。所以 Feign 框架会自己拿到这个类,为它创建独立的子上下文,完全不需要 Spring 扫描。需要在每个需要用到的微服务模块中添加这个注解。从流程可以看出,浏览在访问服务时会携带jwt向微服务发起请求,中间会先经过网关。网关从jwt中获取用户信息并保存到请求中,然后再转发给对应服务。在到达业务层之前会有拦截器将用户信息存入ThreadLocal中。

1.在经过网关过滤器被拦截时将用户信息保存到请求头中

public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) { // 获取request ServerHttpRequest request = exchange.getRequest(); // 判断是否需要拦截 if(isExclude(request.getPath().toString())){ // 无需拦截 放行 return chain.filter(exchange); } // 获取请求头中的token String token = null; List<String> headers = request.getHeaders().get("authorization"); if(CollUtils.isNotEmpty(headers)){ token = headers.get(0); } //校验并解析token Long userId = null; try { userId = jwtTool.parseToken(token); } catch (UnauthorizedException e) { //无效 拦截 ServerHttpResponse response = exchange.getResponse(); response.setRawStatusCode(401); return response.setComplete(); } // 如果有效,传递用户信息 String userInfo = userId.toString(); ServerWebExchange ex = exchange.mutate() .request(b -> b.header("user-info", userInfo)) .build(); // 放行 return chain.filter(exchange); }

由于jwt令牌中会携带用户id,将用户id存入请求头*"user-info"*中;

2.在公用模块中定义拦截器,在拦截器中将请求头中用户信息保存到ThreadLocal中

public class UserInfoInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String userInfo = request.getHeader("user-info"); //保存到ThreadLocal if(StrUtil.isNotBlank(userInfo)){ UserContext.setUser(Long.valueOf(userInfo)); } //放行 return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { //移除用户 UserContext.removeUser(); } }

从*"user-info"*请求头中获取到用户id,将其保存到ThreadLocal中。在经过网关后会先经过该拦截器再到达业务层,从而携带登录用户的id到业务逻辑中。

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

在该模块中定义SpringMVC的配置类,将定义的拦截器注册

697由于是在微服务框架中,在其他启动模块中不会扫描到MvcConfig,所以需要手动配置

3.处理跨服务调用无法拿到用户信息的问题

当基于OpenFeign实现跨服务调用时,从一个服务向另一个服务发送请求时Feign会重新创建一个Http请求,而这个新的请求并不会继承原始的请求头信息。所以需要实现Feign提供的一个拦截器接口:feign.RequestInterceptor

public class DefaultFeignConfig { @Bean public RequestInterceptor userInfoRequestInterceptor(){ return new RequestInterceptor(){ @Override public void apply(RequestTemplate requestTemplate) { //获取登录用户 Long userId = UserContext.getUser(); if(userId == null){ return; } //如果不为空,添加到请求头中 requestTemplate.header("user-info", userId.toString()); } }; } }

在Feign发送Http请求前,通过RequestInterceptor拦截器将请求头添加到Feign创建的请求的头信息中。

由于这是Feign的最佳实践,如果在DefaultFeignConfig类中加了 @Configuration,Spring 组件扫描会把它扫进主容器,里面的 @Bean 就变成全局 Bean 了。而 Feign 的配置类应该只作用于 Feign 自身的上下文,避免污染主容器。所以 Feign 框架会自己拿到这个类,为它创建独立的子上下文,完全不需要 Spring 扫描。需要在每个需要用到的微服务模块中添加这个注解。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/24 23:13:48

游戏任务系统插件Quests 2核心解析:可视化架构与实战开发指南

1. 项目概述&#xff1a;为什么我们需要一个专业的任务系统插件&#xff1f;在游戏开发中&#xff0c;任务系统&#xff08;Quest System&#xff09;是连接玩家与游戏世界、驱动叙事和引导游戏进程的核心骨架。无论是开放世界中的史诗主线&#xff0c;还是角色扮演游戏里的琐碎…

作者头像 李华
网站建设 2026/7/24 23:13:17

车载手持无线吸尘器选购指南:从核心需求到实际体验全解析

这类车载手持无线吸尘器最值得先看的不是功能列表&#xff0c;而是它到底能不能在真实用车和家用场景里稳定解决清洁问题。巴斯这款吸尘器主打16000Pa吸力、紫外线杀菌和多功能切换&#xff0c;但实际使用时&#xff0c;我更关注的是无线续航、吸力持久性、尘盒清理便利性以及不…

作者头像 李华
网站建设 2026/7/24 23:10:11

新一代 Ai coding 工程进阶系列-前言

前言&#xff1a;绝大多数AI开发者&#xff0c;都卡在「只会用、不会建」做AI应用开发、AI Coding落地的这几年&#xff0c;你是不是一直有这种直观感受&#xff1a;明明模型越来越强&#xff0c;但自己写的AI脚本、项目代码&#xff0c;稳定性、复用性、持续性始终上不去&…

作者头像 李华
网站建设 2026/7/24 23:09:15

如何轻松导出原神抽卡记录:新手也能掌握的完整数据分析指南

如何轻松导出原神抽卡记录&#xff1a;新手也能掌握的完整数据分析指南 【免费下载链接】genshin-wish-export Easily export the Genshin Impact wish record. 项目地址: https://gitcode.com/GitHub_Trending/ge/genshin-wish-export 你是否曾经好奇自己在《原神》中到…

作者头像 李华
网站建设 2026/7/24 23:05:55

3个实用技巧,让SharpKeys帮你告别键盘布局烦恼

3个实用技巧&#xff0c;让SharpKeys帮你告别键盘布局烦恼 【免费下载链接】sharpkeys SharpKeys is a utility that manages a Registry key that allows Windows to remap one key to any other key. 项目地址: https://gitcode.com/gh_mirrors/sh/sharpkeys 键盘映射…

作者头像 李华
网站建设 2026/7/24 23:05:27

AI生图总是“多一只手”?教你如何用 Negative Prompt(反向提示词)拯救画面

在AI漫剧和插画创作的实际工作流中&#xff0c;AI生图最经典的翻车现场莫过于人物“多一只手”、“六根手指”或者“双头畸变”。对于追求高效率产出的创作者来说&#xff0c;频繁的抽卡和废图率是极大的时间浪费。要降低这种形变概率&#xff0c;除了依赖底层模型的算法迭代&a…

作者头像 李华