实现步骤
- 实现
UserDetails
,重写getAuthorities
方法。public class LoginUser implements UserDetails { /** * 角色集合 */ private Set<String> roles; @JSONField(serialize = false) private List<SimpleGrantedAuthority> authorities; @Override public Collection<? extends GrantedAuthority> getAuthorities() { if (Objects.nonNull(this.authorities)) { return this.authorities; } authorities = this.roles.stream() .map(role -> new SimpleGrantedAuthority("ROLE_" + role)) .collect(Collectors.toList()); return authorities; } ... }
- 在 SpringSecurity 的配置类上添加注解
@EnableGlobalMethodSecurity
。@Configuration @EnableGlobalMethodSecurity(prePostEnabled = true) public class SecurityConfig extends WebSecurityConfigurerAdapter { ... }
- 在需要权限管理的方法上添加注解
PreAuthorize
,本文使用@hasRole
在方法访问前进行角色校验。@GetMapping("my_info") @PreAuthorize("hasRole('admin')") public Result<User> getMyInfo() { User user = userService.getMyInfo(); return Result.success(user); }
流程分析
- 进行角色校验时,进入到
SecurityExpressionRoot
的hasAnyAuthorityName
方法中。
- 使用
getAuthoritySet
方法获取当前身份验证信息的角色列表,主要代码如下。if (this.roles == null) { Collection<? extends GrantedAuthority> userAuthorities = this.authentication.getAuthorities(); ... // 遍历userAuthorities,通过 GrantedAuthority 的 getAuthority 获取角色字符串,并添加到 set 集合中 this.roles = AuthorityUtils.authorityListToSet(userAuthorities); } return this.roles;
- 遍历
@hasRole
中的角色(本文中只有 admin),如果当前登录信息的角色列表roleSet
包含该角色,则通过校验。
注意:校验时,会自动给 hasRole 中的角色添加默认前缀 ROLE_,所以在重写 getAuthorities 时需要添加上对应前缀