Spring Boot + Security的hasRole与hasAuthority权限控制失效问题
嘿,我一眼就看穿问题根源了——你的Spring Security配置顺序搞反了,再加上UserDetailsService里硬编码了权限,这俩问题叠加起来直接让权限控制完全失效。
核心问题1:HttpSecurity规则顺序错误
Spring Security的授权规则是从上到下依次匹配,一旦匹配到对应规则就会停止后续匹配。你现在的配置里先写了anyRequest().authenticated(),这意味着所有请求只要通过认证就允许访问,后面的/admin/**、/alumno/**这些规则根本不会被执行!这就是Teacher用户能随意访问Admin接口的原因。
修正后的安全配置类
把anyRequest().authenticated()移到所有具体路径规则的后面,同时把密码编码器声明为Bean方便Spring统一管理:
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .authorizeRequests() .antMatchers("/resources/**").permitAll() // 先配置具体路径的权限规则 .antMatchers("/admin/**").hasAuthority("Admin") .antMatchers("/alumno/**").hasAuthority("Student") .antMatchers("/profesor/**").hasAuthority("Teacher") // 最后配置通用规则 .anyRequest().authenticated() .and() .formLogin() .usernameParameter("email") .passwordParameter("password") .loginProcessingUrl("/j_spring_security_check") .loginPage("/login").failureUrl("/login?error=true") .defaultSuccessUrl("/admin/home") .permitAll() .and() .logout() .permitAll(); } @Bean public BCryptPasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } }
核心问题2:UserDetailsService硬编码权限
你的UserDetailsServiceImpl里不管用户实际角色是什么,都硬塞了"Teacher"权限,这会导致所有用户都只有Teacher权限(或者说数据库里的真实角色完全没被读取)。你需要从UsuarioEntity中获取用户的实际角色,再转换为GrantedAuthority。
假设你的UsuarioEntity有getRoles()方法(返回角色列表,比如List<String>),修正后的代码如下:
@Service public class UserDetailsServiceImpl implements UserDetailsService{ @Autowired private UsuarioDao usuarioDao; @Override public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException { UsuarioEntity usuarioEntity = usuarioDao.findByUsuario(username); if (usuarioEntity == null) { throw new UsernameNotFoundException("用户不存在:" + username); } Set<GrantedAuthority> grantedAuthorities = new HashSet<>(); // 从用户实体中读取真实角色,转换为权限对象 for (String role : usuarioEntity.getRoles()) { grantedAuthorities.add(new SimpleGrantedAuthority(role)); } // 注意:数据库中密码必须是BCrypt加密后的字符串,明文会导致认证失败 return new User( usuarioEntity.getUsuario(), usuarioEntity.getPassword(), grantedAuthorities ); } }
关于hasRole()和hasAuthority()的注意点
如果你想用hasRole("Admin"),那么对应的GrantedAuthority需要是"ROLE_Admin"(Spring Security会自动给hasRole的参数加上ROLE_前缀);如果用hasAuthority("Admin"),则直接匹配字符串"Admin"。要确保配置和UserDetailsService中的权限字符串完全一致,不能混用。
测试验证
修改后重启应用:
- 用Admin角色用户登录,应该能正常访问
/admin/home - 用Teacher角色用户登录,访问
/admin/home会被拦截,返回403禁止访问或跳转到登录页
内容的提问来源于stack exchange,提问作者Luisao

