Spring Security微服务安全:JWT与mTLS实践
微服务安全实践:Spring Security在服务通信与网关集成中的深度应用
一、服务间安全通信方案
1. 基于JWT的服务认证
核心原理:服务间通过交换签名令牌建立信任关系,避免频繁的身份验证请求。
// JWT生成示例
public String generateServiceToken() {
return Jwts.builder()
.setSubject("inventory-service") // 服务标识
.setIssuer("auth-center") // 签发方
.setExpiration(new Date(System.currentTimeMillis() + 3600000))
.signWith(SignatureAlgorithm.HS512, secretKey)
.compact();
}
// JWT验证过滤器
public class JwtServiceFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain chain) {
String token = request.getHeader("X-Service-Token");
Claims claims = Jwts.parser()
.setSigningKey(secretKey)
.parseClaimsJws(token)
.getBody();
if (!"auth-center".equals(claims.getIssuer())) {
throw new JwtException("Invalid issuer");
}
// 建立服务身份上下文
ServiceAuthentication auth = new ServiceAuthentication(claims.getSubject());
SecurityContextHolder.getContext().setAuthentication(auth);
chain.doFilter(request, response);
}
}
实践建议:
- 使用非对称加密(如RSA)替代HS512增强安全性
- 服务标识采用URN格式(如
urn:service:order
) - 令牌有效期控制在1小时以内,配合刷新机制
2. 双向TLS(mTLS)配置
实现步骤:
生成证书(示例使用OpenSSL):
# 生成CA根证书 openssl req -x509 -newkey rsa:4096 -days 365 -nodes -keyout ca-key.pem -out ca-cert.pem # 生成服务端证书 openssl req -newkey rsa:4096 -nodes -keyout server-key.pem -out server-req.pem openssl x509 -req -in server-req.pem -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem # 生成客户端证书(同理)
Spring Boot配置:
# application.yml server: ssl: enabled: true key-store: classpath:keystore.p12 key-store-password: changeit key-alias: server client-auth: need # 开启双向验证 trust-store: classpath:truststore.p12 trust-store-password: changeit
通信流程:
实践建议:
- 使用证书指纹校验增强安全性
- 通过Kubernetes Cert-Manager实现证书自动轮换
- 开发环境可使用
trustAll
配置快速验证(生产环境禁用)
二、网关安全集成方案
1. Spring Cloud Gateway权限传递
典型架构:
关键配置:
// 网关JWT解析配置
public class SecurityConfig {
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity http) {
return http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/auth/**").permitAll()
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtDecoder(jwtDecoder())
)
)
.build();
}
@Bean
public ReactiveJwtDecoder jwtDecoder() {
return NimbusReactiveJwtDecoder.withPublicKey(publicKey).build();
}
}
// 转发用户信息的全局过滤器
public class UserInfoForwardFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
return exchange.getPrincipal()
.cast(JwtAuthenticationToken.class)
.flatMap(token -> {
// 添加用户信息到请求头
exchange.getRequest().mutate()
.header("X-User-Id", token.getToken().getSubject())
.header("X-User-Roles", String.join(",",
token.getAuthorities().stream()
.map(GrantedAuthority::getAuthority)
.collect(Collectors.toList())))
.build();
return chain.filter(exchange);
});
}
}
2. 下游服务用户上下文透传
方案对比:
方案 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
请求头传递 | 实现简单,性能好 | 信息量有限,需防篡改 | 简单用户信息传递 |
JWT令牌转发 | 自包含签名,安全性高 | 令牌膨胀问题 | 需要完整身份信息的场景 |
上下文服务 | 集中管理,灵活性高 | 增加依赖和延迟 | 复杂上下文管理 |
最佳实践示例:
// 下游服务接收用户上下文
@RestController
public class OrderController {
@GetMapping("/orders")
public ResponseEntity<?> getOrders(@RequestHeader("X-User-Id") String userId) {
// 业务处理...
}
// 更优雅的方式 - 自定义参数解析器
@GetMapping("/v2/orders")
public ResponseEntity<?> getOrdersV2(@CurrentUser User user) {
// 业务处理...
}
}
// 自定义参数解析器
public class CurrentUserArgumentResolver implements HandlerMethodArgumentResolver {
@Override
public boolean supportsParameter(MethodParameter parameter) {
return parameter.hasParameterAnnotation(CurrentUser.class);
}
@Override
public Object resolveArgument(MethodParameter parameter,
ModelAndViewContainer mavContainer,
NativeWebRequest webRequest,
WebDataBinderFactory binderFactory) {
String userId = webRequest.getHeader("X-User-Id");
String roles = webRequest.getHeader("X-User-Roles");
return new User(userId, Arrays.asList(roles.split(",")));
}
}
安全增强建议:
- 对敏感头信息(如X-User-Id)进行HMAC签名验证
- 网关层实施速率限制防止信息泄露攻击
- 使用B3 Propagation格式实现全链路安全跟踪
三、生产环境注意事项
密钥管理:
- 使用HashiCorp Vault或AWS KMS管理加密密钥
- 实现密钥自动轮换策略
性能优化:
// JWT验证缓存示例 @Bean public JwtDecoder cachedJwtDecoder() { return new CachingJwtDecoder( NimbusJwtDecoder.withPublicKey(publicKey).build(), Duration.ofMinutes(30) ); }
监控指标:
- 认证失败率(/actuator/metrics/security.authentication.failure)
- JWT过期告警
- mTLS握手成功率
灾备方案:
- 双活证书颁发机构(CA)
- 本地缓存应急令牌
- 服务降级白名单机制
通过以上方案的综合应用,可构建既安全又高效的微服务通信体系。建议根据实际业务场景选择合适的安全级别,避免过度设计带来的复杂性。
评论已关闭