背景

本文是《Java 后端从小白到大神》修仙系列之框架学习,Spring Cloud 微服务实战系列的 第六篇。Spring Cloud 是构建微服务架构的基石,拥有完整的服务治理生态,在云原生架构中广泛应用。本系列将从架构认知到实际工程,逐步构建一套企业级 Spring Cloud 微服务项目。若想详细学习请点击首篇博文开始,现在开始学习。

文章概览

微服务安全体系设计:JWT + 网关鉴权 + 上下文传递:

  1. JWT 基础结构与签名机制
  2. 登录服务颁发 Token + 过期策略设计
  3. Gateway 中统一认证与白名单机制
  4. Feign 请求中的 Token 透传机制
  5. 用户上下文统一提取与安全注入模型

1. JWT 基础结构与签名机制

JWT 即 JSON Web Token,由 Header + Payload + Signature 组成:

  • Header: 声明签名算法 (HS256)
  • Payload: 包含用户 ID,角色,账号类型
  • Signature: 加密(Header + Payload + 私钥)

使用 JWT 可以无独缓存 Token,分布式无依赖,适合微服务。

2. 登录服务符发 Token 和过期策略

在 auth-service 服务中,进行用户合法性校验后,输出 JWT Token:

1
2
3
4
5
6
String token = Jwts.builder()
    .setSubject(userId)
    .setIssuedAt(new Date())
    .setExpiration(DateUtil.offsetHour(new Date(), 2))
    .signWith(SignatureAlgorithm.HS256, secretKey)
    .compact();

策略推荐:

  • 短效 Token (2h) + RefreshToken 刷新
  • 前端随身保存,后端无独缓存

3. Gateway 网关统一鉴权 + 白名单

在 gateway-service 中通过 GlobalFilter 扩展:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
@Component
public class AuthFilter implements GlobalFilter {
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getPath().toString();
        if (whiteList.contains(path)) return chain.filter(exchange);

        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (JwtUtil.validate(token)) {
            String userId = JwtUtil.extractUserId(token);
            exchange.getRequest().mutate().header("X-User-Id", userId);
            return chain.filter(exchange);
        } else {
            return unauthorized(exchange);
        }
    }
}

4. Feign 中 Token 送出 (上下文传递)

通过 user-api 模块公用 Feign 抽象,在下游服务中得到 Token 信息。

1
2
3
4
5
6
7
8
9
@Configuration
public class FeignInterceptor implements RequestInterceptor {
    @Override
    public void apply(RequestTemplate template) {
        String token = RequestContextHolder.getRequestAttributes()
              .getAttribute("Authorization", RequestAttributes.SCOPE_REQUEST);
        if (token != null) template.header("Authorization", token.toString());
    }
}

5. 用户上下文统一接入:SecurityContext

通过 ThreadLocal 和 Filter 解析 token,在 user-service/task-service 中统一输入:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
public class UserContextFilter extends OncePerRequestFilter {
    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
            throws ServletException, IOException {
        String token = request.getHeader("Authorization");
        if (JwtUtil.validate(token)) {
            UserDTO user = JwtUtil.parse(token);
            UserContext.set(user);
        }
        chain.doFilter(request, response);
    }
}

应用于 Controller / Feign fallback / RabbitMQ 解耦等场景。

总结

本篇以创建 auth-service 为实例

  • auth-service: 进行 JWT Token 登录证明
  • gateway-service: 增加 GlobalFilter 校验 + header 送出
  • user-api: 增加 FeignInterceptor 扩展
  • user-service / task-service: 未创建,待后篇实现

至此、一套经过 JWT 签名,网关转发,上下文添加和 Feign 传递的安全化模型已实现,为后续的链路跟踪,分布式交易,统一日志打了基础。