配置两个Spring Security安全配置类时出现Unauthorized错误排查
配置错误原因及修正方案
错误点梳理
- 未给每套安全配置限定处理的路径范围
Spring Security的多套安全链按@Order优先级顺序匹配请求,@Order值越小优先级越高,未显式标注的WebSecurityConfigurerAdapter默认优先级为100。你当前的两个配置都没有添加根路径匹配规则,只要优先级更高的配置匹配到请求,后续的配置就完全不会生效。从你的现象来看Customer配置优先级更高,所有请求都走它的校验逻辑,Employee配置全程不生效。 - Customer安全配置的路径权限规则书写错误
你在Customer配置的authorizeRequests下写了.antMatchers("/customers/**")后,没有紧跟该路径的权限规则,直接写了.anyRequest().authenticated(),这行路径匹配完全没有生效,等于所有路径只要登录就可以访问,所以Customer用户可以无限制访问/inventory/**路径。 - 多套安全配置的用户池默认隔离
每个WebSecurityConfigurerAdapter的AuthenticationManager是独立的,只会用自身配置的用户池做校验,因此Employee的用户在Customer配置的用户池中不存在,请求全部返回401。
修正方案
调整优先级,给每个配置添加根路径匹配限定各自处理的路径范围,同时修正Customer的权限规则即可:
// 客户侧安全配置,仅处理/customers/**路径 @Configuration @Order(2) // 优先级低于员工侧配置 public class CustomerSecurityAppConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("user1") .password("{noop}password") .and() .withUser("user2") .password("{noop}password"); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.cors().disable(); // 限定当前配置只处理/customers/**开头的请求 http.antMatcher("/customers/**") .authorizeRequests() .anyRequest() .authenticated() .and() .formLogin() .and() .httpBasic(); } } // 员工侧安全配置,仅处理/inventory/**路径 @Configuration @Order(1) // 优先级更高,优先匹配/inventory/**的请求 class EmployeeSecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth .inMemoryAuthentication() .withUser("admin") .password("{noop}password") .roles("USER", "ADMIN") .and() .withUser("user") .password("{noop}password") .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.csrf().disable(); http.cors().disable(); // 限定当前配置只处理/inventory/**开头的请求 http.antMatcher("/inventory/**") .authorizeRequests() .antMatchers(HttpMethod.GET, "/inventory/**") .hasAnyRole("USER", "ADMIN") .antMatchers(HttpMethod.POST, "/inventory/**") .hasRole("ADMIN") .anyRequest() .authenticated() .and() .formLogin() .and() .httpBasic(); } }
修正后效果:
- Customer用户(user1、user2)只能正常访问
/customers/**路径,访问/inventory/**会走员工侧校验逻辑,因不在员工用户池返回401 - Employee用户(admin、user)只能正常访问
/inventory/**路径,访问/customers/**会走客户侧校验逻辑,因不在客户用户池返回401 - 完全符合两套realm分别处理不同业务场景的需求
内容的提问来源于stack exchange,提问作者zilcuanu
相关产品推荐
相关产品推荐

