
本文详解如何在 Spring Cloud 微服务架构中正确配置 API 网关与微服务两级安全策略,解决 /public/users/** 等端点因网关拦截导致的 401 Unauthorized 问题。核心在于:网关层应放行路由路径,微服务层再按业务路径精细化授权。
本文详解如何在 spring cloud 微服务架构中正确配置 api 网关与微服务两级安全策略,解决 `/public/users/**` 等端点因网关拦截导致的 `401 unauthorized` 问题。核心在于:网关层应放行路由路径,微服务层再按业务路径精细化授权。
在基于 Spring Cloud + Keycloak 的微服务架构中,一个常见但易被忽视的问题是:即使微服务的 SecurityFilterChain 明确对 /public/users/** 调用了 .permitAll(),前端访问仍返回 401 Unauthorized。根本原因并非配置错误,而是安全拦截发生在请求抵达微服务之前——即 API 网关未放行对应路由路径,导致 JWT 认证在网关层已失败,请求甚至未转发至微服务。
✅ 正确分层安全设计原则
-
API 网关层(认证入口):负责统一身份验证(如 JWT 校验)、路由转发与粗粒度路径放行(如
/user-service/**)。它不处理角色权限,只确保合法令牌进入系统。 -
微服务层(授权执行):接收已认证的请求,基于
@PreAuthorize或SecurityFilterChain进行细粒度授权(如hasRole('ADMIN')),并对/public/**等路径明确permitAll()。
? 关键修复步骤
1. 网关层:放行整个服务路由前缀
在 SecurityWebFilterChain 中,必须允许所有发往用户服务的请求通过认证检查(因为网关需先解码并验证 JWT,再转发):
@Bean
public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity security) {
return security
.csrf().disable()
.authorizeExchange(exchange -> exchange
.pathMatchers("/eureka/**").permitAll() // Eureka 健康检查
.pathMatchers("/user-service/v0.1-dev/**").permitAll() // ✅ 关键:放行整个微服务路由前缀
.anyExchange().authenticated()) // 其他路径需认证
.oauth2ResourceServer(spec -> spec.jwt()) // 统一 JWT 校验
.build();
}⚠️ 注意:
/user-service/v0.1-dev/**必须与RouteLocator中定义的path()完全一致(包括版本号),否则放行失效。
2. 微服务层:专注业务级授权逻辑
微服务的 SecurityFilterChain 仅处理已成功转发的请求,按实际业务路径授权:
@Bean
public SecurityFilterChain securedSecurityFilterChain(HttpSecurity http) throws Exception {
http
.csrf().disable() // WebFlux 网关下微服务通常无需 CSRF
.authorizeHttpRequests(authz -> authz
.requestMatchers("/public/users/**").permitAll() // ✅ 公共端点:PUT/POST/DELETE 均放行
.requestMatchers("/auth/admins/users/**").hasRole("ADMIN")
.requestMatchers("/auth/subscribers/users/**").hasRole("SUBSCRIBER")
.anyRequest().authenticated()
)
.oauth2ResourceServer(oauth2 -> oauth2
.jwt(jwt -> jwt
.jwtAuthenticationConverter(authenticationConverter)
)
);
return http.build();
}? 提示:路径匹配器(如
/public/users/**)作用于微服务接收到的相对路径(即http://ms:8080/public/users/xxx),而非网关暴露的完整路径(/user-service/v0.1-dev/public/users/xxx)。
? 常见误区与避坑指南
- ❌ 在网关层对
/user-service/v0.1-dev/public/users/**单独permitAll()—— 无效,因为网关的authorizeExchange匹配的是入站请求路径,而路由规则已将该路径重写为微服务内部路径,网关无法感知下游的/public/结构。 - ❌ 在微服务 Controller 上使用
@PermitAll(Jakarta EE 注解)—— Spring Security 不识别此注解,必须通过SecurityFilterChain或@PreAuthorize("permitAll()")控制。 - ❌ 启用 CSRF(尤其 WebFlux 网关场景)—— 网关与微服务均为无状态 REST API,CSRF 无意义且干扰 JWT 流程,务必禁用。
✅ 最终请求流验证
- 客户端请求
GET /user-service/v0.1-dev/public/users/123 - 网关:匹配
/user-service/v0.1-dev/**→permitAll()→ 校验 JWT 合法性 → 转发至lb://user-service - 微服务:收到
GET /public/users/123→SecurityFilterChain匹配/public/users/**→ 放行 → 执行业务逻辑
遵循“网关认证、微服务授权”的分层原则,即可彻底解决公共端点 401 问题,同时保障系统安全性与可维护性。

















