Spring Security自定义Provider下@PreAuthorize校验返回403问题求助
看起来你遇到的是Spring Security方法级权限校验不生效的问题——明明控制台显示用户拥有CORBEILLES_GESTION权限,但访问对应接口时却返回403。让我帮你拆解下问题根源和解决办法:
问题根源
从你的控制台输出userPrincipal Authorities = [[GESTION_UTILISATEURS, MODIFICATION_CE, CREATION_CE, CORBEILLES_GESTION, GESTION_ROLES]]能看出关键问题:
你的权限集合里只有一个GrantedAuthority实例,这个实例把所有权限打包在了一起(toString()显示为包含多个权限的数组)。
而Spring Security的hasAuthority()表达式的校验逻辑是:检查用户的权限集合中是否存在一个GrantedAuthority对象,其getAuthority()方法返回的字符串完全等于指定的权限字符串(这里是CORBEILLES_GESTION)。
显然你的单个GrantedAuthority返回的是多个权限的组合字符串(比如"[GESTION_UTILISATEURS, MODIFICATION_CE,...]"),并不是单独的"CORBEILLES_GESTION",所以校验失败,返回403。
这个问题出在CSEUserDetailsService的getAuthorities私有方法上——你没有把每个权限单独封装成SimpleGrantedAuthority实例。
解决方案
修改CSEUserDetailsService中的getAuthorities方法,确保每个权限都对应一个独立的SimpleGrantedAuthority对象:
假设你的utilisateur.getRoles()返回的是包含所有权限字符串的集合(比如Set<String>),推荐用Stream流的简洁写法:
import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.stream.Collectors; // ... 其他类代码 private Collection<? extends GrantedAuthority> getAuthorities(Set<String> roles) { // 遍历每个权限字符串,创建独立的SimpleGrantedAuthority实例 return roles.stream() .map(SimpleGrantedAuthority::new) .collect(Collectors.toList()); }
如果习惯传统循环写法,也可以这样实现:
import org.springframework.security.core.authority.SimpleGrantedAuthority; // ... 其他类代码 private Collection<? extends GrantedAuthority> getAuthorities(Set<String> roles) { List<GrantedAuthority> authorities = new ArrayList<>(); for (String role : roles) { authorities.add(new SimpleGrantedAuthority(role)); } return authorities; }
验证修改效果
修改后重启应用并登录,控制台输出的权限应该变成类似:
DEBUG : userPrincipal Authorities = [GESTION_UTILISATEURS, MODIFICATION_CE, CREATION_CE, CORBEILLES_GESTION, GESTION_ROLES]
(注意这里没有外层的方括号,每个权限都是独立的GrantedAuthority实例)
此时再访问http://localhost:8080/myappli/corbeilles/professions,@PreAuthorize("hasAuthority('CORBEILLES_GESTION')")就能正确匹配权限,不会再返回403错误了。
内容的提问来源于stack exchange,提问作者Minuitchan

