You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security配置问题:无法开放指定端点的公共访问权限

公共端点401问题排查(Spring Cloud Gateway + Keycloak + 微服务)

我在微服务架构中遇到了公共端点无法开放的问题:用Keycloak实现的角色认证功能正常,但标注了.permitAll()的公共端点始终返回401 Unauthorized。架构使用Spring Cloud API网关做请求路由和负载均衡。

已尝试的解决方案

  • 先在API网关层实现认证,无论如何配置,访问微服务端点全返回401,放弃该方案
  • 改为在微服务层实现认证,角色认证生效,但公共端点的401问题依旧
  • 在微服务的SecurityFilterChain里禁用CSRF,无任何变化
  • 移除微服务里的公共端点配置,转到API网关的SecurityWebFilterChain中配置,问题仍存在
  • 给PublicUserController的端点添加javax.annotation.security.PermitAll注解,无效

用户服务(User Service)代码

SecurityConfiguration

说明:尝试开放/public/users/**路径,支持PUT、DELETE、POST请求

@Configuration
@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)
public class SecurityConfiguration {

    private final AuthenticationConverter authenticationConverter;

    @Autowired
    public SecurityConfiguration(AuthenticationConverter authenticationConverter) {
        this.authenticationConverter = authenticationConverter;
    }

    @Bean
    public SecurityFilterChain securedSecurityFilterChain(HttpSecurity http) throws Exception {
        http.authorizeHttpRequests(request -> request
                        .requestMatchers("/public/users/**").permitAll()
                        .requestMatchers("/admins/users/**").hasRole("ADMIN")
                        .requestMatchers("/subscribers/users/**").hasRole("SUBSCRIBER")
                        .anyRequest().authenticated())
                .oauth2ResourceServer()
                .jwt()
                .jwtAuthenticationConverter(authenticationConverter);

        return http.build();
    }
}

API网关(Api Gateway)代码

UserServiceRouteConfiguration

@Configuration
public class UserServiceRouteConfiguration {

    private final String API_VERSION = "v0.1-dev";

    @Bean
    public RouteLocator userServiceRouteLocator(RouteLocatorBuilder builder) {
        return builder.routes()
                .route("user-service", route -> route
                        .path("/user-service/" + API_VERSION + "/subscribers/users/**")
                        .and().method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE)
                        .uri("lb://user-service"))
                .route("user-service", route -> route
                        .path("/user-service/" + API_VERSION + "/admins/users/**")
                        .and().method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE)
                        .uri("lb://user-service"))
                .route("user-service", route -> route
                        .path("/user-service/" + API_VERSION + "/public/users/**")
                        .and().method(HttpMethod.GET, HttpMethod.PUT, HttpMethod.POST, HttpMethod.DELETE)
                        .uri("lb://user-service"))
                .build();
    }
}

SecurityConfiguration

说明:最初在这里实现角色认证,但未生效

@Configuration
@EnableWebFluxSecurity
public class SecurityConfiguration {

    @Bean
    public SecurityWebFilterChain springSecurityFilterChain(ServerHttpSecurity security) {
        return security.csrf().disable()
                .authorizeExchange(exchange -> exchange
                        .pathMatchers("/eureka/**").permitAll()
                        .anyExchange().authenticated())
                .oauth2ResourceServer(ServerHttpSecurity.OAuth2ResourceServerSpec::jwt)
                .build();
    }
}

排查方向建议

  1. 路径匹配一致性检查
    网关路由的路径是/user-service/v0.1-dev/public/users/**,但微服务配置的是/public/users/**。如果网关未做路径重写,微服务实际收到的请求路径带前缀,导致/public/users/**无法匹配,触发anyRequest().authenticated()。可以在网关路由添加.filters(f -> f.stripPrefix(2))(去除/user-service/v0.1-dev两个前缀段),或微服务路径改为/**/public/users/**测试。

  2. API网关认证拦截优先级
    当前网关的SecurityWebFilterChain配置了.anyExchange().authenticated(),所有请求都会先被网关拦截校验,包括公共端点。即使微服务配置了permitAll,未带token的请求已被网关返回401。需将公共端点路径加入网关的permitAll:

    .authorizeExchange(exchange -> exchange
            .pathMatchers("/eureka/**").permitAll()
            .pathMatchers("/user-service/" + API_VERSION + "/public/users/**").permitAll()
            .anyExchange().authenticated())
    
  3. JWT转换器影响排查
    检查authenticationConverter是否强制要求请求携带token,导致无token的公共端点请求被拦截。可临时注释掉.jwtAuthenticationConverter(authenticationConverter),测试公共端点是否能正常访问,排查转换器是否存在问题。

  4. SecurityFilterChain优先级
    确认是否存在多个SecurityFilterChain Bean,导致当前的securedSecurityFilterChain未生效。可给该Bean添加@Order(1)注解,确保其优先级高于其他配置。

  5. 请求方法匹配验证
    网关路由指定了允许的请求方法,确认测试请求的方法是否在允许范围内(比如是否使用了PATCH方法但网关未配置),导致请求被网关拦截。

内容的提问来源于stack exchange,提问作者charbs29

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 15:44:54