Spring Security双登录表单loginProcessingUrl失效致404问题求助
解决Spring Security多登录表单404问题
问题根源
你的用户/管理员登录处理URL(/userLogin、/adminLogin)不在对应过滤器链的securityMatcher匹配范围内(/user/**、/admin/**),导致负责处理登录的过滤器链不会拦截这些请求,最终请求落到GeneralSecurityConfig中,但该链未配置登录处理逻辑,直接返回404。
修复方案
1. 调整登录处理URL与过滤器匹配规则
将登录处理URL调整到对应角色的路径下,并修改securityMatcher包含登录页面和登录处理路径,确保对应过滤器链能拦截这些请求。
2. 修改Security配置类代码
package com.business.config; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.annotation.Order; import org.springframework.security.authentication.AuthenticationManager; import org.springframework.security.authentication.dao.DaoAuthenticationProvider; import org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.business.service.impl.UserDetailsServiceImpl; @Configuration @EnableWebSecurity public class SecurityConfiguration { @Autowired UserDetailsServiceImpl userDetailService; @Bean public static BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public DaoAuthenticationProvider authProvider() { DaoAuthenticationProvider provider = new DaoAuthenticationProvider(); provider.setUserDetailsService(userDetailService); provider.setPasswordEncoder(passwordEncoder()); return provider; } @Bean public AuthenticationManager authenticationManager(AuthenticationConfiguration authenticationConfiguration) throws Exception { return authenticationConfiguration.getAuthenticationManager(); } @Order(1) public static class UserSecurityConfig { @Bean public SecurityFilterChain filterChain1(HttpSecurity http) throws Exception { http // 匹配用户相关的登录、页面及资源路径 .securityMatcher("/user/**", "/user-login", "/user/login") .authorizeHttpRequests(auth -> auth .requestMatchers("/user-login", "/user/login").permitAll() .requestMatchers("/user/**").hasRole("USER") ) .formLogin(form -> form .loginPage("/user-login") .loginProcessingUrl("/user/login") .usernameParameter("email") .passwordParameter("password") .defaultSuccessUrl("/user/home") .permitAll() ) .logout(logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/user/logout")) .logoutSuccessUrl("/") ) .exceptionHandling(ex -> ex .accessDeniedPage("/403") ); return http.build(); } } @Order(2) public static class AdminSecurityConfig { @Bean public SecurityFilterChain filterChain2(HttpSecurity http) throws Exception { http // 匹配管理员相关的登录、页面及资源路径 .securityMatcher("/admin/**", "/admin-login", "/admin/login") .authorizeHttpRequests(auth -> auth .requestMatchers("/admin-login", "/admin/login").permitAll() .requestMatchers("/admin/**").hasRole("ADMIN") ) .formLogin(form -> form .loginPage("/admin-login") .loginProcessingUrl("/admin/login") .usernameParameter("email") .passwordParameter("password") .defaultSuccessUrl("/admin/home") .permitAll() ) .logout(logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout")) .logoutSuccessUrl("/") ) .exceptionHandling(ex -> ex .accessDeniedPage("/403") ); return http.build(); } } @Order(3) public static class GeneralSecurityConfig { @Bean public SecurityFilterChain filterChain3(HttpSecurity http) throws Exception { http .csrf().disable() .headers().frameOptions().disable() .and() .authorizeHttpRequests(auth -> auth // 仅允许公共路径,避免覆盖前面的权限规则 .requestMatchers("/", "/css/**", "/js/**", "/images/**", "/user-register", "/admin-register").permitAll() // 未匹配到的其他请求需要认证 .anyRequest().authenticated() ); return http.build(); } } }
3. 修改登录页面表单提交地址
管理员登录页面调整表单action:
<form th:action="@{/admin/login}" method="post">
用户登录页面同理修改为@{/user/login}。
关键说明
securityMatcher必须包含登录页面和登录处理URL,确保对应过滤器链能处理登录请求;hasRole("USER")等价于检查ROLE_USER权限,Spring会自动添加ROLE_前缀,无需手动书写;- 区分用户和管理员的登出路径,避免不同角色登出时产生冲突;
- 通用过滤器链不要使用
"/**"匹配所有请求,否则会覆盖前面的权限规则,仅开放公共资源即可。
内容的提问来源于stack exchange,提问作者Thomas Shelby
相关产品推荐
相关产品推荐

