在 Spring Cloud Gateway 中实现 JWT 验证和用户信息提取,核心思路是在网关层通过全局过滤器拦截请求,统一完成认证,再将解析出的用户信息传递给下游微服务。这样做既能保障安全,又能避免每个微服务重复处理认证逻辑。
下面我们通过一个具体的流程,并结合关键代码示例来详细说明如何实现。
🚀 核心实现步骤
整个实现流程主要包含网关层的认证过滤器和微服务层的用户信息接收两部分,其核心交互与数据流转如下图所示:

💻 关键代码实现
1. 网关层:创建 JWT 全局认证过滤器
这是实现的核心,负责校验令牌并传递用户信息。
java
@Component
@RequiredArgsConstructor
public class JwtAuthGlobalFilter implements GlobalFilter, Ordered {
private final JwtUtils jwtUtils; // 自定义的JWT工具类
private final AuthProperties authProperties; // 配置类,存放排除路径
private final AntPathMatcher antPathMatcher = new AntPathMatcher();
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
ServerHttpRequest request = exchange.getRequest();
String path = request.getPath().toString();
// 1. 检查是否为无需认证的路径(如登录接口)
if (isExclude(path)) {
return chain.filter(exchange);
}
// 2. 从Authorization请求头中提取JWT
String token = extractToken(request.getHeaders());
if (token == null) {
return unauthenticated(exchange, "Missing token");
}
try {
// 3. 验证并解析JWT
Claims claims = jwtUtils.parseToken(token);
if (jwtUtils.isTokenExpired(token)) {
return unauthenticated(exchange, "Token expired");
}
// 4. 提取用户信息,并添加到新的请求头中,传递给下游服务
String userId = claims.getSubject();
String roles = claims.get("roles", String.class);
ServerWebExchange mutatedExchange = exchange.mutate().request(originalRequest ->
originalRequest.header("X-User-Id", userId)
.header("X-User-Roles", roles)
).build();
// 5. 放行请求
return chain.filter(mutatedExchange);
} catch (Exception e) {
return unauthenticated(exchange, "Invalid token");
}
}
private boolean isExclude(String path) {
return authProperties.getExcludePaths().stream()
.anyMatch(pattern -> antPathMatcher.match(pattern, path));
}
private String extractToken(HttpHeaders headers) {
String authHeader = headers.getFirst(HttpHeaders.AUTHORIZATION);
if (authHeader != null && authHeader.startsWith("Bearer ")) {
return authHeader.substring(7);
}
return null;
}
private Mono<Void> unauthenticated(ServerWebExchange exchange, String message) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
DataBuffer buffer = exchange.getResponse().bufferFactory()
.wrap(String.format("{"code": 401, "msg": "%s"}", message).getBytes());
return exchange.getResponse().writeWith(Mono.just(buffer));
}
@Override
public int getOrder() {
return -1; // 设置较高的优先级
}
}
代码主要参考了和中的实现思路。
2. 微服务层:使用拦截器接收用户信息
下游微服务需要接收并保存用户信息,方便业务代码使用。
a. 创建用户上下文(UserContext)
使用 ThreadLocal
确保每个请求的用户信息线程隔离。
typescript
public class UserContext {
private static final ThreadLocal<Map<String, String>> CONTEXT = new ThreadLocal<>();
public static void setUserInfo(Map<String, String> userInfo) {
CONTEXT.set(userInfo);
}
public static String getUserId() {
Map<String, String> userInfo = CONTEXT.get();
return userInfo != null ? userInfo.get("userId") : null;
}
public static void clear() {
CONTEXT.remove();
}
}
代码主要参考了和中的实现思路。
b. 创建用户信息拦截器
typescript
@Component
public class UserInfoInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
// 从网关添加的请求头中获取用户信息
String userId = request.getHeader("X-User-Id");
String roles = request.getHeader("X-User-Roles");
if (userId != null) {
Map<String, String> userInfo = new HashMap<>();
userInfo.put("userId", userId);
userInfo.put("roles", roles);
// 将用户信息存入上下文
UserContext.setUserInfo(userInfo);
}
return true;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
// 请求完成后务必清理ThreadLocal,防止内存泄漏
UserContext.clear();
}
}
代码主要参考了和中的实现思路。
c. 注册拦截器
typescript
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Autowired
private UserInfoInterceptor userInfoInterceptor;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(userInfoInterceptor).addPathPatterns("/api/**");
}
}
⚙️ 配置说明
在 application.yml
中配置排除路径和路由规则。
yaml
auth:
exclude-paths:
- "/api/auth/login"
- "/api/public/**"
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://user-service
predicates:
- Path=/api/users/**
filters:
- StripPrefix=1
配置思路参考了和。
⚠️ 重要实践建议
- 安全第一 :务必使用 HTTPS 来传输 JWT。JWT 的签名密钥要有足够的强度,并定期更换。
- 性能优化:对于高并发场景,可以考虑在网关层对 JWT 的解析结果进行短期缓存(如使用 Caffeine),避免重复解析。
- 令牌管理:为 JWT 设置合理的过期时间(如 1-2 小时)。对于需要主动撤销令牌的场景(如用户退出登录),可以结合 Redis 维护一个短期的令牌黑名单。
- 清晰界定职责 :网关负责认证 (Authentication,即"你是谁"),微服务负责授权(Authorization,即"你能干什么")。权限判断逻辑建议放在微服务内。
💎 总结
通过以上步骤,你就可以在 Spring Cloud Gateway 中构建一个统一、安全、高效的 JWT 认证和用户信息传递机制。这种架构确保了安全逻辑的集中管理,同时让业务微服务能专注于核心功能。