Spring Boot配置Spring Security后无法访问/admin路径下控制器接口
问题原因排查
1. 角色/权限匹配规则错误
Spring Security 中hasRole()和hasAuthority()的校验逻辑有本质区别:
- 使用
hasRole("ADMIN")时,框架会自动拼接ROLE_前缀,实际校验的是用户是否拥有ROLE_ADMIN权限 - 使用
hasAuthority("ADMIN")时,直接和用户的权限字符串完全匹配
如果你数据库/用户权限配置里存的权限是没有ROLE_前缀的ADMIN,用hasRole("ADMIN")肯定匹配失败,反之如果存的带前缀用hasAuthority也会失败。
2. 权限规则顺序冲突
Spring Security的antMatchers是从上到下按顺序匹配,匹配到第一个规则就生效,后面的规则直接忽略。
你的初始配置里写了.antMatchers("/**").permitAll()之后又写了.anyRequest().authenticated(),后者完全不会生效。如果此时你访问/admin路径时已经登录,但权限不对,就会直接跳403;如果没登录的话按理说应该放通,但如果前面的/admin/**规则命中了,就会先校验权限,没权限就403。
你的第二个配置里也有同样的问题,/**.permitAll()如果写在后面的话,前面的/admin/**规则是生效的,如果你没登录或者权限不对就会被拦截。
3. 自定义登录页路由不存在
你修改后的配置指定了loginPage("/signin"),如果没有实现对应的/signin接口/视图,访问需要权限的路由时会直接跳转到不存在的/signin,看起来就像admin路由访问失败。
4. 用户权限返回错误
检查你自定义的UserDetailsServiceImpl中,返回的UserDetails对象的getAuthorities()方法是否正确返回了对应的权限,比如是否真的给管理员用户返回了ADMIN/EDITOR的权限,有没有拼写错误。
解决方案
按以下步骤依次修改测试:
- 统一权限校验规则,调整规则顺序
如果你存的权限没有ROLE_前缀,就统一用hasAuthority,不要混用hasRole,权限规则严格按范围从小到大的顺序排列,范围越大的规则越靠后:
@Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/new").hasAnyAuthority("ADMIN", "CREATOR") .antMatchers("/admin/**").hasAnyAuthority("ADMIN", "EDITOR") .antMatchers("/delete/**").hasAuthority("ADMIN") // 公共资源放这里,比如静态资源、登录页、错误页等 .antMatchers("/signin", "/static/**", "/403").permitAll() // 剩下的所有请求需要登录 .anyRequest().authenticated() .and() .formLogin() .loginPage("/signin") .defaultSuccessUrl("/home") .permitAll() .and() .logout().permitAll() .and() .exceptionHandling().accessDeniedPage("/403") .and() .csrf().disable(); }
- 检查UserDetailsServiceImpl的权限返回逻辑
确保给对应用户返回的权限集合是正确的,参考写法:
@Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { User user = userRepository.findByUsername(username); if (user == null) { throw new UsernameNotFoundException("用户不存在"); } List<GrantedAuthority> authorities = Arrays.stream(user.getRoles().split(",")) .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); return new org.springframework.security.core.userdetails.User(user.getUsername(), user.getPassword(), authorities); }
- 确认登录页路由存在
确保你有对应的控制器处理/signin请求,返回对应的登录视图。 - 排查阶段可以临时给
/admin/**配置permitAll,如果能正常访问就可以确认是权限配置的问题,如果还是不能访问再排查控制器扫描、路径拼写的问题。
内容的提问来源于stack exchange,提问作者348_Amit Potdukhe.
相关产品推荐
相关产品推荐

