Spring Security FilterChain执行异常:跨角色访问返回404求助
问题原因分析
当前配置存在两个核心问题:
- 每个
SecurityFilterChain仅匹配各自模块的路径前缀(/admin/**、/guest/**),对应的登录页(/admin_login、/guest_login)不在匹配范围内,虽不影响正常登录,但会导致权限校验逻辑覆盖不全。 - 当已登录用户访问对方模块资源时,系统检测到权限不足后,会跳转到未实现的
/access-denied页面,因此返回404;而预期逻辑是清除当前登录状态,重定向到对应身份的登录页。
解决方案
修改两个SecurityFilterChain配置,调整路径匹配范围、放行登录页访问,并自定义权限不足时的跳转逻辑:
修改后的SecurityConfigOrder1类
package com.securityexample; 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.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.securityexample.providers.MyCustomAuthenticationProvider; @Configuration @EnableWebSecurity @Order(1) public class SecurityConfigOrder1 { @Autowired MyCustomAuthenticationProvider myCustomeAuthenticationProvider; @Bean public SecurityFilterChain filterChainApp1(HttpSecurity http) throws Exception { http.authenticationProvider(myCustomeAuthenticationProvider); // 匹配/admin路径下资源及管理员登录页 http.requestMatchers(request -> request.matches("/admin/**", "/admin_login")) .authorizeRequests(auth -> auth .antMatchers("/admin_login").permitAll() // 放行登录页匿名访问 .anyRequest().hasAuthority("ADMIN")) .formLogin(form -> form .loginPage("/admin_login") .loginProcessingUrl("/admin/process-login") .failureUrl("/admin_login?error=error") .defaultSuccessUrl("/admin/page1") .usernameParameter("username") .passwordParameter("password")) .logout(logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/admin/logout")) .logoutSuccessUrl("/admin_login?logout=true") .deleteCookies("JSESSIONID")) .exceptionHandling(ex -> ex // 管理员访问访客资源时,销毁会话并重定向到访客登录页 .accessDeniedHandler((request, response, exDenied) -> { request.getSession().invalidate(); response.sendRedirect("/guest_login"); })) .csrf(csrf -> csrf.disable()); return http.build(); } }
修改后的SecurityConfigOrder2类
package com.securityexample; 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.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.web.SecurityFilterChain; import org.springframework.security.web.util.matcher.AntPathRequestMatcher; import com.securityexample.providers.GuestAuthenticationProvider; @Configuration @EnableWebSecurity @Order(2) public class SecurityConfigOrder2 { @Autowired GuestAuthenticationProvider guestAuthenticationProvider; @Bean public SecurityFilterChain filterChaninApp2(HttpSecurity http) throws Exception { http.authenticationProvider(guestAuthenticationProvider); // 匹配/guest路径下资源及访客登录页 http.requestMatchers(request -> request.matches("/guest/**", "/guest_login")) .authorizeRequests(auth -> auth .antMatchers("/guest_login").permitAll() // 放行登录页匿名访问 .anyRequest().hasAuthority("GUEST_USER")) .formLogin(form -> form .loginPage("/guest_login") .loginProcessingUrl("/guest/process-login") .failureUrl("/guest_login?error=error") .defaultSuccessUrl("/guest/page1") .usernameParameter("username") .passwordParameter("otp")) .logout(logout -> logout .logoutRequestMatcher(new AntPathRequestMatcher("/guest/logout")) .logoutSuccessUrl("/guest_login?logout=true") .deleteCookies("JSESSIONID")) .exceptionHandling(ex -> ex // 访客访问管理员资源时,销毁会话并重定向到管理员登录页 .accessDeniedHandler((request, response, exDenied) -> { request.getSession().invalidate(); response.sendRedirect("/admin_login"); })) .csrf(csrf -> csrf.disable()); return http.build(); } }
关键调整说明
- 路径匹配范围扩展:使用
requestMatchers替代antMatcher,让过滤器链同时处理模块资源和对应登录页,避免逻辑遗漏。 - 登录页匿名放行:对
/admin_login和/guest_login添加permitAll(),确保未登录用户能正常访问登录页面。 - 自定义权限不足处理:通过
accessDeniedHandler销毁当前会话(清除已登录状态),并重定向到目标身份的登录页,完全符合需求预期。
内容的提问来源于stack exchange,提问作者vickykr26941
相关产品推荐
相关产品推荐

