Spring Security 5.x升级至6.x后,POST /login请求返回404错误
Spring Security 5.x升级至6.x后,POST /login请求返回404错误
我帮你分析下这个问题的核心原因:你把formLogin配置和OAuth2授权服务器的配置绑定在了同一个SecurityFilterChain里,再加上securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())的限制,导致处理POST /login的UsernamePasswordAuthenticationFilter根本没被应用到这个请求上,自然就返回404了。
具体来说,securityMatcher(authorizationServerConfigurer.getEndpointsMatcher())会让当前FilterChain只对OAuth2授权服务器的专属端点生效(比如/oauth2/authorize、/oauth2/token这类),而你的登录配置是挂在这个链上的,所以当你提交POST /login时,这个请求不会匹配到这个FilterChain,也就没有对应的过滤器来处理登录逻辑,直接返回404。
解决方案:拆分独立的SecurityFilterChain
你需要把普通Web安全配置(登录、静态资源放行、自定义登录页)和OAuth2授权服务器配置拆分成两个独立的SecurityFilterChain Bean,让它们各自负责不同的请求范围。Spring Security 6.x会按@Order注解的优先级(数字越小,优先级越高)来匹配请求。
修改后的完整配置代码如下:
@Configuration @EnableWebSecurity public class DefaultSecurityConfig { private final ThrottlingFilter throttlingFilter; private final UserRepository userRepository; DefaultSecurityConfig(ThrottlingFilter throttlingFilter, UserRepository userRepository) { this.throttlingFilter = throttlingFilter; this.userRepository = userRepository; } // 普通Web安全FilterChain:处理登录、静态资源等非授权服务器请求 @Bean @Order(1) // 优先级高于授权服务器FilterChain(默认Order为100) public SecurityFilterChain webSecurityFilterChain(HttpSecurity http) throws Exception { http .formLogin(form -> form .loginPage("/portal-login") // 自定义登录页 .loginProcessingUrl("/login") // 显式指定登录处理URL,避免配置歧义 .permitAll() ) .addFilterBefore(throttlingFilter, UsernamePasswordAuthenticationFilter.class) .authorizeHttpRequests(authorize -> authorize .requestMatchers(HttpMethod.OPTIONS).permitAll() .requestMatchers(HttpMethod.GET, "/index*", "/static/**", "/*.js", "/*.json", "/*.ico", "/rest", "/*logo*.png" ).permitAll() .requestMatchers("/aps/v1/featureFlag/isEnabled/**").permitAll() .anyRequest().authenticated() ) .cors(Customizer.withDefaults()); return http.build(); } // OAuth2授权服务器专属FilterChain:仅处理授权服务器端点 @Bean @Order(2) public SecurityFilterChain authorizationServerSecurityFilterChain( HttpSecurity http, JpaRegisteredClientRepository jpaRegisteredClientRepository, JpaOAuth2AuthorizationService jpaOAuth2AuthorizationService ) throws Exception { OAuth2AuthorizationServerConfigurer authorizationServerConfigurer = OAuth2AuthorizationServerConfigurer.authorizationServer(); http .securityMatcher(authorizationServerConfigurer.getEndpointsMatcher()) .with(authorizationServerConfigurer, authorizationServer -> { authorizationServer .oidc(Customizer.withDefaults()) // 启用OpenID Connect 1.0 .registeredClientRepository(jpaRegisteredClientRepository) .authorizationService(jpaOAuth2AuthorizationService); }) .authorizeHttpRequests(authorize -> authorize .anyRequest().authenticated() ); return http.build(); } @Bean UserDetailsService userDetailsService() { return username -> { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("User details not found for user: " + username); } return new ApsUserPrincipal( user.getId(), user.getUsername(), user.getPassword(), user.getEmail(), user.getEnabled() > 0, user.getFirstName(), user.getLastName(), user.getRole(), user.getFiId(), user.getCountry() ); }; } }
关键修改说明
- 拆分FilterChain:把原有的单一配置拆成两个独立Bean,分别处理普通Web请求和授权服务器请求
- 优先级控制:用
@Order指定执行顺序,普通Web链先匹配,确保登录请求被优先处理 - 调整formLogin位置:把登录配置移到普通Web链中,让
UsernamePasswordAuthenticationFilter正确注册并处理POST /login请求 - 显式指定登录URL:虽然默认处理URL就是
/login,但显式声明可以避免配置歧义
额外检查点
- 确认你的自定义登录页表单的
action为"/login",method为POST,例如:
<form action="/login" method="post"> <input type="text" name="username" placeholder="用户名"> <input type="password" name="password" placeholder="密码"> <button type="submit">登录</button> </form>
- 确保没有其他配置类或过滤器拦截了
/login请求
备注:内容来源于stack exchange,提问作者MOHAMMAD WASEEM
相关产品推荐
相关产品推荐

