在SpringSecurity中,会使用默认的FilterSecurityInterceptor来进行权限校验。在FilterSecurityInterceptor中会从SecurityContextHolder获取其中的Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。
所以我们在项目中只需要把当前登录用户的权限信息也存Authentication,然后设置我们的资源所需要的权限即可。
想开启授权,首先SecurityConfig配置类上加上该条注释
@EnableGlobalMethodSecurity(prePostEnabled = true)
然后在需要控制的接口上加入注释
//参数就为自己像设置的权限
@PreAuthorize("hasAuthority('test')")
我们靠最开始实现 UserDetails 的 LoginUser类中实现的方法返回权限
@Data
@NoArgsConstructor
public class LoginUser implements UserDetails {
private User user;
//重写的UserDetailsServiceImpl中不仅要返回用户基本信息,还要返回权限信息
private List<String> permissions;
@JSONField(serialize = false) //SimpleGrantedAuthority是由spring管理,我们会把LoginUser存入redis中,则redis不会序列化SimpleGrantedAuthority
//则我们不把该对象存入到redis中,则加入该注释
private List<SimpleGrantedAuthority> authorities;
public LoginUser(User user,List<String> permissions){
this.user = user;
this.permissions = permissions;
}
//springSecurity中权限信息是通过重写该方法传递出去
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//已进入就有权限信息,则不需要再去数据库访问一次了
if(authorities!=null){
return authorities;
}
//把permission中String类型的权限信息封装成SimpleGrantedAuthority对象
authorities = new ArrayList<>();
for(String permission : permissions){
SimpleGrantedAuthority authority = new SimpleGrantedAuthority(permission);
authorities.add(authority);
}
return authorities;
}
@Override
public String getPassword() {
return user.getPassword();
}
@Override
public String getUsername() {
return user.getUserName();
}
@Override
public boolean isAccountNonExpired() {
return true;
}
@Override
public boolean isAccountNonLocked() {
return true;
}
@Override
public boolean isCredentialsNonExpired() {
return true;
}
@Override
public boolean isEnabled() {
return true;
}
}
然后在从数据库那用户数据的地方再拿权限信息即可(该代码中只是随便给了一个list,没有从数据库中拿值)
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Autowired
private UserMapper userMapper;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LambdaQueryWrapper<User> queryWrapper = new LambdaQueryWrapper<>();
queryWrapper.eq(User::getUserName,username);
User user =userMapper.selectOne(queryWrapper);
if(Objects.isNull(user)){
throw new RuntimeException("用户名或者密码错误");
}
//todo 封装权限信息
List<String> list = new ArrayList<>(Arrays.asList("test","admin"));
//数据返回UserDetails类型,把数据封装成UserDetails类型 但UserDetails是接口,则利用一个UserDetails的实现类,我们自己写一个实现类去实现该接口就行,重写里面的方法
return new LoginUser(user,list);
}
}