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

Spring Security授权服务器permitAll配置不生效问题排查

问题描述

我正在使用Spring Authorization Server,现有两个控制器:/user/**和/client/**。预期需求为:/user/**可公开访问,/client/**仅允许已认证用户访问。我配置了两条过滤器链:一条用于授权服务器,将未认证的/client/**请求重定向到/login;另一条处理登录页重定向。但实际访问/user/**时,却被重定向到/login页面。

配置代码

@Configuration
public class WebSecurityConfig {

    @Order(1)
    @Bean
    SecurityFilterChain authServerFilterChain(HttpSecurity http, JwtAuthenticationConverter jwtAuthenticationConverter) throws Exception {
    
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());
    
        http.exceptionHandling(ex -> ex.defaultAuthenticationEntryPointFor(
                        new LoginUrlAuthenticationEntryPoint("/login"),
                   // redirect all unautheticated /client/** to login
                        new AntPathRequestMatcher("/client/**")
    
             ))
            .oauth2ResourceServer(rs -> rs.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter)));

        return http.build();
    }

    @Order(2)
    @Bean
    SecurityFilterChain defaultFilterChain(HttpSecurity http, CorsConfigurationSource corsConfigurationSource) throws Exception {
        http
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
                .csrf(csrf -> csrf.disable())
                .cors(cors -> cors.configurationSource(corsConfigurationSource))
                .authorizeHttpRequests(
                        req -> req.requestMatchers("/user/**").permitAll()
                                .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults());
        return http.build();
    }
    
    @Bean
    AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder()
                .build();
    }

}

用户端点代码

@Controller
@ResponseBody
@RequestMapping("/user/")
public class UserController {

    private final UserService userService;

    public UserController(UserService userService) {
        this.userService = userService;
    }

    @GetMapping()
    public String hello() {
        return "Hello from User Controller";
    }
}

调试日志

2024-09-22T14:23:35.456+05:30  INFO 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring DispatcherServlet 'dispatcherServlet'
2024-09-22T14:23:35.457+05:30  INFO 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Initializing Servlet 'dispatcherServlet'
2024-09-22T14:23:35.459+05:30  INFO 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet        : Completed initialization in 2 ms
2024-09-22T14:23:35.492+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing GET /user
2024-09-22T14:23:35.508+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2024-09-22T14:23:35.512+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Secured GET /user
2024-09-22T14:23:35.548+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing GET /error
2024-09-22T14:23:35.549+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2024-09-22T14:23:35.553+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-1] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://localhost:8080/login
2024-09-22T14:23:35.580+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-2] o.s.security.web.FilterChainProxy        : Securing GET /login
2024-09-22T14:23:35.810+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-3] o.s.security.web.FilterChainProxy        : Securing GET /favicon.ico
2024-09-22T14:23:35.811+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-3] o.s.s.w.a.AnonymousAuthenticationFilter  : Set SecurityContextHolder to anonymous SecurityContext
2024-09-22T14:23:35.812+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-3] o.s.s.web.DefaultRedirectStrategy        : Redirecting to http://localhost:8080/login
2024-09-22T14:23:35.825+05:30 DEBUG 131685 --- [spring-oauth2-auth-server] [nio-8080-exec-4] o.s.security.web.FilterChainProxy        : Securing GET /login

问题原因与解决方案

原因分析

从日志可见,/user请求本身已被放行,但后续触发了/error请求,该请求被重定向到登录页。核心问题有两个:

  1. 默认过滤器链设置了SessionCreationPolicy.STATELESS无状态会话策略,但表单登录依赖会话管理,两者冲突导致请求处理出错,触发错误页面。
  2. 授权服务器过滤器链未限定匹配路径,会处理所有请求,包括/user,虽然未拦截,但后续默认过滤器链的会话配置问题引发了连锁错误。

修复步骤

  1. 调整会话策略:表单登录需要会话支持,将默认过滤器链的SessionCreationPolicy.STATELESS改为SessionCreationPolicy.IF_REQUIRED(默认值),或直接移除该配置。
  2. 限定授权服务器过滤器链的处理路径:让它只处理授权服务器相关路径和/client/**,避免无关请求进入该链。

修改后的配置代码:

@Configuration
public class WebSecurityConfig {

    @Order(1)
    @Bean
    SecurityFilterChain authServerFilterChain(HttpSecurity http, JwtAuthenticationConverter jwtAuthenticationConverter) throws Exception {
        // 限定该过滤器链仅处理指定路径
        http.securityMatcher("/oauth2/**", "/client/**", "/login/**", "/error/**");
        
        OAuth2AuthorizationServerConfiguration.applyDefaultSecurity(http);
    
        http.getConfigurer(OAuth2AuthorizationServerConfigurer.class)
                .oidc(Customizer.withDefaults());
    
        http.exceptionHandling(ex -> ex.defaultAuthenticationEntryPointFor(
                        new LoginUrlAuthenticationEntryPoint("/login"),
                        new AntPathRequestMatcher("/client/**")
             ))
            .oauth2ResourceServer(rs -> rs.jwt(jwt -> jwt.jwtAuthenticationConverter(jwtAuthenticationConverter)));

        return http.build();
    }

    @Order(2)
    @Bean
    SecurityFilterChain defaultFilterChain(HttpSecurity http, CorsConfigurationSource corsConfigurationSource) throws Exception {
        http
                // 移除无状态配置,使用默认的IF_REQUIRED支持表单登录
                .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED))
                .csrf(csrf -> csrf.disable())
                .cors(cors -> cors.configurationSource(corsConfigurationSource))
                .authorizeHttpRequests(
                        req -> req.requestMatchers("/user/**").permitAll()
                                .anyRequest().authenticated())
                .formLogin(Customizer.withDefaults());
        return http.build();
    }
    
    @Bean
    AuthorizationServerSettings authorizationServerSettings() {
        return AuthorizationServerSettings.builder()
                .build();
    }

}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 06:24:52