微服务架构中的 Token 工作机制详解

news/2025/11/15 17:12:27/文章来源:https://www.cnblogs.com/Quazjq1207/p/19225852

引言

在微服务架构中,用户身份认证和授权是系统安全的核心挑战。由于服务被拆分成多个独立的微服务,传统的基于 Session 的认证方式无法满足分布式环境的需求。Token 机制(特别是 JWT)成为微服务架构中实现无状态身份认证的主流方案。本文将深入解析 Token 在微服务中的完整生命周期和工作机制。

一、Token 的生成与前端存储

1.1 Token 的生成时机

Token 在用户登录成功后生成,具体流程如下:

  1. 用户提交凭证:用户通过前端提交用户名和密码到认证服务
  2. 凭证验证:认证服务验证用户信息(查询数据库或调用用户服务)
  3. Token 生成:验证通过后,认证服务生成包含用户身份信息的 Token
  4. 返回前端:认证服务将 Token 返回给前端

常见的 Token 类型

  • JWT:自包含令牌,包含用户信息、签名和过期时间
  • UUID令牌:随机字符串,需与后端存储的用户信息关联

1.2 前端 Token 存储机制

前端收到 Token 后,需要妥善存储并在后续请求中自动携带:

// 登录成功后存储 Token
const login = async (credentials) => {const response = await fetch('/api/auth/login', {method: 'POST',body: JSON.stringify(credentials)});const { token } = await response.json();// 存储到 localStorage 或 sessionStoragelocalStorage.setItem('auth_token', token);// 或设置 Cookie(自动携带)document.cookie = `auth_token=${token}; path=/; max-age=86400`;
};// 为所有请求自动添加 Token
axios.interceptors.request.use(config => {const token = localStorage.getItem('auth_token');if (token) {config.headers.Authorization = `Bearer ${token}`;}return config;
});

二、Token 在微服务间的传递机制

2.1 API 网关:统一入口和认证

微服务架构通常通过 API 网关作为统一入口:

# Spring Cloud Gateway 配置示例
spring:cloud:gateway:routes:- id: user-serviceuri: lb://user-servicepredicates:- Path=/api/users/**filters:- name: AuthFilter# 网关统一认证,验证 Token 有效性

网关负责:

  • 验证 Token 签名和有效期
  • 路由请求到正确的微服务
  • 传递原始请求头(包括 Token)

2.2 服务间调用的 Token 自动传递

2.2.1 Feign 客户端的 Token 拦截器

@Component
public class FeignTokenInterceptor implements RequestInterceptor {@Overridepublic void apply(RequestTemplate template) {// 从当前线程的 UserContext 获取 TokenUserInfo userInfo = UserContext.get();if (userInfo != null && userInfo.getToken() != null) {template.header("Authorization", "Bearer " + userInfo.getToken());}}
}

2.2.2 RestTemplate 的 Token 拦截器

@Configuration
public class RestTemplateConfig {@Bean@LoadBalancedpublic RestTemplate restTemplate() {RestTemplate restTemplate = new RestTemplate();restTemplate.getInterceptors().add((request, body, execution) -> {UserInfo userInfo = UserContext.get();if (userInfo != null && userInfo.getToken() != null) {request.getHeaders().add("Authorization", "Bearer " + userInfo.getToken());}return execution.execute(request, body);});return restTemplate;}
}

2.3 Token 传递的完整链条

前端 → 网关 → 服务A → 服务B → 服务C↓      ↓      ↓      ↓      ↓Token  Token  Token  Token  Token↓      ↓      ↓      ↓      ↓
携带   验证并  从请求头 从请求头 从请求头转发   提取并  提取并  提取并存储到   存储到   存储到TL     TL     TL

三、微服务内的用户上下文管理

3.1 UserContext 与 ThreadLocal 设计

/*** 用户上下文管理类*/
public class UserContext {private static final ThreadLocal<UserInfo> currentUser = new ThreadLocal<>();public static void set(UserInfo user) {currentUser.set(user);}public static UserInfo get() {return currentUser.get();}public static void clear() {currentUser.remove();}// 便捷方法public static Long getUserId() {UserInfo user = get();return user != null ? user.getUserId() : null;}public static String getUsername() {UserInfo user = get();return user != null ? user.getUsername() : null;}
}/*** 用户信息封装类*/
@Data
public class UserInfo {private Long userId;private String username;private String token;private List<String> roles;private List<String> permissions;// 其他用户相关信息
}

3.2 请求拦截器:Token 解析与上下文设置

@Component
public class AuthenticationInterceptor implements HandlerInterceptor {@Autowiredprivate JwtTokenProvider tokenProvider;@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {// 从请求头提取 TokenString token = extractToken(request);if (token != null && tokenProvider.validateToken(token)) {// 解析 Token 获取用户信息UserInfo userInfo = tokenProvider.getUserInfoFromToken(token);userInfo.setToken(token);// 设置到当前线程的 UserContextUserContext.set(userInfo);} else {// Token 无效,返回 401response.setStatus(HttpStatus.UNAUTHORIZED.value());return false;}return true;}@Overridepublic void afterCompletion(HttpServletRequest request,HttpServletResponse response, Object handler, Exception ex) {// 请求完成后清理 ThreadLocal,防止内存泄漏UserContext.clear();}private String extractToken(HttpServletRequest request) {String bearerToken = request.getHeader("Authorization");if (StringUtils.hasText(bearerToken) && bearerToken.startsWith("Bearer ")) {return bearerToken.substring(7);}return null;}
}

3.3 业务代码中的用户信息获取

@RestController
@RequestMapping("/api/orders")
public class OrderController {@Autowiredprivate OrderService orderService;@GetMapping("/my-orders")public ResponseEntity<List<Order>> getUserOrders() {// 直接从 UserContext 获取当前用户信息Long userId = UserContext.getUserId();String username = UserContext.getUsername();List<Order> orders = orderService.getOrdersByUserId(userId);return ResponseEntity.ok(orders);}
}@Service
public class OrderService {public List<Order> getOrdersByUserId(Long userId) {// 服务层也可以直接获取用户上下文String currentUser = UserContext.getUsername();log.info("用户 {} 查询订单,目标用户ID: {}", currentUser, userId);// 业务逻辑...return orderRepository.findByUserId(userId);}
}

四、特殊场景处理

4.1 异步调用中的 Token 传递

@Service
public class AsyncService {@Asyncpublic CompletableFuture<String> asyncProcess() {try {// 手动传递 Token 到异步线程String token = AsyncContext.getToken();if (token != null) {UserInfo userInfo = parseToken(token); // 解析 TokenUserContext.set(userInfo);}// 异步业务逻辑String result = doHeavyProcessing();return CompletableFuture.completedFuture(result);} finally {UserContext.clear(); // 清理上下文}}
}/*** 异步上下文传递工具类*/
public class AsyncContext {private static final ThreadLocal<String> asyncToken = new ThreadLocal<>();public static void setToken(String token) {asyncToken.set(token);}public static String getToken() {return asyncToken.get();}public static void clear() {asyncToken.remove();}
}// 在调用异步方法前设置 Token
@Service
public class OrderService {@Autowiredprivate AsyncService asyncService;public void processOrderAsync(Order order) {// 从当前上下文获取 Token 并设置到异步上下文String token = UserContext.get().getToken();AsyncContext.setToken(token);// 调用异步方法asyncService.asyncProcess();// 清理异步上下文AsyncContext.clear();}
}

4.2 网关层面的统一认证与 Token 中继

@Component
public class GatewayAuthFilter implements GlobalFilter, Ordered {@Overridepublic Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {ServerHttpRequest request = exchange.getRequest();// 提取 TokenString token = extractToken(request);if (token != null) {// 验证 Token(可选:可转发到认证服务验证)if (validateToken(token)) {// 将用户信息添加到请求头,传递给下游服务ServerHttpRequest mutatedRequest = request.mutate().header("X-User-Id", extractUserId(token)).header("X-Username", extractUsername(token)).build();return chain.filter(exchange.mutate().request(mutatedRequest).build());}}// Token 无效,返回 401ServerHttpResponse response = exchange.getResponse();response.setStatusCode(HttpStatus.UNAUTHORIZED);return response.setComplete();}// 其他工具方法...
}

五、安全最佳实践

5.1 Token 安全配置

@Configuration
public class JwtConfig {@Value("${jwt.secret}")private String secret;@Value("${jwt.expiration}")private Long expiration;@Beanpublic JwtTokenProvider jwtTokenProvider() {return new JwtTokenProvider(secret, expiration);}
}@Component
public class JwtTokenProvider {private final String secret;private final Long expiration;public JwtTokenProvider(String secret, Long expiration) {this.secret = secret;this.expiration = expiration;}public String generateToken(UserDetails userDetails) {Map<String, Object> claims = new HashMap<>();claims.put("userId", userDetails.getUserId());claims.put("roles", userDetails.getRoles());return Jwts.builder().setClaims(claims).setSubject(userDetails.getUsername()).setIssuedAt(new Date()).setExpiration(new Date(System.currentTimeMillis() + expiration)).signWith(SignatureAlgorithm.HS512, secret).compact();}public boolean validateToken(String token) {try {Jwts.parser().setSigningKey(secret).parseClaimsJws(token);return true;} catch (Exception e) {return false;}}
}

5.2 防范常见安全威胁

  1. 使用 HTTPS 防止 Token 被窃听
  2. 设置合理的过期时间 减少 Token 泄露风险
  3. 实现 Token 刷新机制 平衡安全性与用户体验
  4. 使用 HttpOnly Cookie 防范 XSS 攻击

六、完整工作流程总结

  1. 生成阶段:用户登录 → 认证服务生成 Token → 返回前端存储
  2. 传递阶段:前端携带 Token → 网关验证 → 服务间自动传递
  3. 上下文阶段:各服务解析 Token → 设置 ThreadLocal → 业务使用
  4. 清理阶段:请求完成 → 清理 ThreadLocal → 释放资源

结论

微服务架构中的 Token 工作机制通过"传递+解析+上下文管理"的模式,实现了分布式的无状态认证。关键在于:

  1. 标准化传递:通过 HTTP 头跨服务一致传递
  2. 自动化管理:通过拦截器自动处理 Token 传递和解析
  3. 线程级隔离:通过 ThreadLocal 实现请求级别的用户上下文隔离
  4. 安全加固:通过签名、过期时间等措施保证 Token 安全性

这种机制既保证了微服务架构的松散耦合特性,又提供了统一的身份认证方案,是现代分布式系统的重要基础设施。

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

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

相关文章

[KaibaMath]1023 柯西不等式的简洁证明

柯西不等式是数学中最基础的不等式之一,建立了“平方和的乘积”与 “乘积和的平方”之间的不等关系,其形式简洁,实用性极强。下面给出其简洁证明。

2025 最新网架厂家权威排行榜:焊接球 / 螺栓球 / 大跨度等多类型网架实力企业最新推荐

引言 随着大型建筑、工业设施、公共场馆等项目的蓬勃发展,网架作为核心承重结构,其质量、精度与定制化能力直接决定工程成败。当前网架市场品牌繁杂,部分厂家存在技术滞后、产能不足、售后薄弱等问题,导致客户在选…

WEB集群-HTTP概述与Nginx部署

1.WEB集群-HTTP协议 1.HTTP概述默认端口是80HTTP超文本传输协议: 数据请求与响应传输:网站的数据如何传递给用户. 超文本:文本,图片,视频.... 用户打开网站后:网站如何传递数据给用户. 专业名字:数据请求与响应.请求re…

实战内容

JWTtoken的token过期问题 本地时钟与远程服务器时钟对应不上导致JWTtoken的异常过期问题。

2025 最新无缝钢管厂家推荐榜:国际测评认证 + 技术创新 + 全场景适配权威指南

引言 无缝钢管作为工业制造、能源输送等核心领域的关键材料,其品质直接影响下游产业安全运行。本次推荐榜基于国际钢铁协会(World Steel Association)与国际钢管行业协会(ISSF)联合 SGS、Intertek 两大检测机构的…

【Qt开发】多元素类控件(二)-> QTableWidget - 实践

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

BBS伪随机数生成器

Blum Blum Shub(BBS),由Lenore Blum、Manuel Blum和Michael Shub于1986年提出。BBS伪随机数生成器以其可证明的安全性而闻名,其安全性基于大整数分解问题的困难性 BBS生成器的数学基础 1. Blum整数 BBS生成器的核心…

[KaibaMath]1022 一道平面几何题的两种解法

本文给出一道平面几何题的两种解法。第一种解法基于初等数学,第二种则基于高等数学。(该题目的解答完成于2017年)

实用指南:从0开始了解kafka《第二篇 kafka的安装、管理和配置》

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

动态规划法

动态规划法一、按照动态规划法的求解步骤分析作业题目“数字三角形”: 1.1 根据最优子结构性质,列出递归方程式,说明方程式的定义、边界条件: 从三角形顶部出发,每次只能向下或向右下移动,最终到达底部时,找到一…

函数表达式:JavaScript中那些你不知道的优雅写法 - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

11.15模拟赛

t1 小 \(\mathrm{L}\) 有一串 \(n\) 块宝石的项链, 它可以顺时针看成一个圆环, 即第 1 块宝石与第 2 块和第 \(n\) 块宝石相邻, 第 2 块宝石与第 1 块和第 3 块宝石相邻, 以此类推。 但不幸的是, 项链的宝石破碎了。每…

2025 最新无缝钢管优质厂家推荐:国际测评认证 + 技术创新 + 全场景适配 + 服务保障综合榜单

引言 本榜单基于国际钢管行业协会(ISSF)最新测评数据编制,通过三大核心维度构建权威评价体系:技术实力(占比 40%)涵盖生产工艺先进性、定制化能力及检测设备精度;产品品质(占比 35%)依据力学性能、尺寸公差、…

西门子S7200_SMART仿真软件的使用(保姆级教程)

第一步:编写一个简单的程序用于测试 第二步:导出“.awl”格式的文件第三步:双击打开软件包里的“S7_200汉化版.exe” 第四步:输入密码“6596”并点击“确定” 第五步:选择与之对应的CPU型号 第六步:点击“程序…

2025年RS485红外线测温仪源头厂家权威推荐榜单:在线红外测温仪/20mA红外线测温仪/红外线测温仪变送器源头厂家精选

在工业自动化与智能制造的浪潮下,RS485红外测温仪因其信号传输稳定、抗干扰能力强且便于组网的优势,市场需求持续增长。选择合适的RS485接口、支持Modbus-RTU协议的红外测温仪,已成为工业现场实现可靠温度监控的关键…

P14508 猜数游戏 guess

每次通过一些特别的手法可以知道一个长度的区间内是否有东西。 那么设 \(f_i\) 为长度为 \(i\) 的区间最少花费,那么每次将其划分成两个区间,看其中需要确定一个的最小花费是什么,这是好做的(因为确定了一个区间就…

AMD Instinct MI50 通过llama.cpp 在 ROCm7.0.2上运行

关于网上传言MI50 ROCm7.0.2的性能提升了,这边做了下测试。 ROCm7.0.2安装方法: ROCm 7.0 Install for Mi50 32GB | Ubuntu 24.04 LTS : r/LocalLLaMA 这边系统使用的ubuntu22.04 ROCm安装 wget https://repo.radeon.…

如何成为高级的安卓逆向工程师 glm4.6

如何成为高级的安卓逆向工程师 glm4.6如何成为高级的安卓逆向工程师 ● Ill help you understand how to become a senior Android reverse engineer. Let me create a comprehensive roadmap for you. ● 成为高级安…

PyTorch实战(9)——从零开始实现Transformer - 教程

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

天津雅思培训机构排名2025,无老师国际/新通教育等优质机构,师资/口碑/提分率大PK

天津雅思培训机构排名2025,无老师国际/新通教育等优质机构,师资/口碑/提分率大PK随着留学申请热度的持续攀升,雅思成绩已成为学子们海外深造的“通行证”,天津地区雅思培训市场也随之蓬勃发展。专业的雅思培训机构…