题目
如何设计一个基于Spring Cloud Gateway的微服务统一鉴权方案?
信息
- 类型:问答
- 难度:⭐⭐
考点
Spring Cloud Gateway, OAuth2/JWT, 微服务安全, 过滤器链设计, 服务间通信
快速回答
实现统一鉴权需要结合以下核心组件:
- 使用Spring Cloud Gateway作为API网关,统一拦截请求
- 通过自定义GlobalFilter实现JWT令牌校验
- 采用OAuth2资源服务器配置验证令牌有效性
- 使用Feign拦截器传递认证信息到下游服务
- 关键配置:
spring.security.oauth2.resourceserver.jwt.issuer-uri指向授权服务器
1. 核心原理
在微服务架构中,统一鉴权通过API网关集中处理认证,避免每个服务重复实现安全逻辑。流程如下:
- 客户端携带JWT访问网关
- 网关验证JWT签名和有效期
- 网关将用户信息注入请求头转发到微服务
- 微服务通过Feign客户端传递认证上下文
2. 代码实现示例
网关过滤器 (JwtAuthFilter.java)
@Component
public class JwtAuthFilter implements GlobalFilter {
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
String token = extractToken(exchange.getRequest());
if (token == null) {
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
return exchange.getResponse().setComplete();
}
try {
// 使用JwtDecoder验证令牌
Jwt jwt = jwtDecoder.decode(token);
// 将用户信息添加到请求头
exchange.mutate().request(builder ->
builder.header("X-User-Id", jwt.getSubject())
).build();
} catch (JwtException e) {
exchange.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
return exchange.getResponse().setComplete();
}
return chain.filter(exchange);
}
}资源服务配置 (ResourceServerConfig.java)
@Configuration
@EnableWebFluxSecurity
public class ResourceServerConfig {
@Bean
SecurityWebFilterChain securityFilterChain(ServerHttpSecurity http) {
http
.authorizeExchange(exchanges -> exchanges
.pathMatchers("/public/**").permitAll()
.anyExchange().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt.jwtDecoder(jwtDecoder()))
);
return http.build();
}
@Bean
public JwtDecoder jwtDecoder() {
return JwtDecoders.fromIssuerLocation("http://auth-service");
}
}3. 最佳实践
- 密钥管理:使用非对称加密(RS256),授权服务保管私钥,网关/微服务使用公钥验证
- 令牌传递:通过请求头
Authorization: Bearer <token>传递,避免URL参数泄露 - 性能优化:网关缓存公钥,避免每次请求都向授权服务查询
- 安全增强:校验令牌颁发者(iss)、受众(aud)等声明(claims)
4. 常见错误
- 错误1:未校验令牌签名 - 导致伪造令牌可绕过验证
解决方案:确保配置jwtDecoder并验证签名 - 错误2:下游服务重复鉴权 - 增加延迟
解决方案:微服务仅需解析X-User-Id头,不再完整验证JWT - 错误3:未处理令牌过期 - 引发401错误
解决方案:前端实现令牌刷新逻辑,网关拦截401响应触发刷新流程
5. 扩展知识
- 服务间调用鉴权:使用Spring Cloud OpenFeign添加请求拦截器自动传递JWT
- 权限控制:在网关层通过
ReactiveAuthorizationManager实现基于角色的预鉴权 - 限流熔断:结合Sentinel在网关层对未授权请求进行限流,防止暴力破解
- 替代方案:当需要复杂权限策略时,可集成Keycloak或Okta等专业IAM服务