授权
权限系统要实现的效果:不同的用户可以使用不同的功能。
在后台进行用户权限的判断,判断当前用户是否有相应的权限,必须具有所需权限才能进行相应的操作。
在 SpringSecurity 中,默认使用 FilterSecurityInterceptor 进行权限校验。在 FilterSecurityInterceptor 中会从SecurityContextHolder 获取其中的 Authentication,然后获取其中的权限信息。当前用户是否拥有访问当前资源所需的权限。所以我们在项目中只需要把当前登录用户的权限信息也存入 Authentication,然后设置我们的资源所需要的权限即可。
首先开启相关配置。
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
// ......
}
使用对应的注解。@PreAuthorize
@RestController
@RequestMapping("/user")
public class SysUserController {
@Resource
private SysUserService sysUserService;
// 登录方法......
// 退出登录......
@GetMapping("/list")
@PreAuthorize("hasAuthority('USER1')")
public ResultJSON list() {
return ResultJSON.success();
}
}
封装权限信息
写 UserDetailsServiceImzho 中,在查询出用户后还要获取对应的权限信息,封装到 UserDetails 中返回。
把权限信息写死封装到 UserDetails 中进行测试。
修改 UserDetails 的实现类 LoginUser,让其能封装权限信息。
@Data
@NoArgsConstructor
@AllArgsConstructor
public class LoginUser implements UserDetails {
private SysUser sysUser;
private List<String> permissions;
public LoginUser(SysUser sysUser, List<String> permissions) {
this.sysUser = sysUser;
this.permissions = permissions;
}
//存储SpringSecurity所需要的权限信息的集合
@JSONField(serialize = false)
private List<GrantedAuthority> authorities;
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
if (authorities != null) {
return authorities;
}
authorities = AuthorityUtils.commaSeparatedStringToAuthorityList(String.join(",",permissions));
return authorities;
}
// 其他方法......
}
@Service
public class UserDetailsServiceImpl implements UserDetailsService {
@Resource
private SysUserDao sysUserDao;
@Override
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
// 根据用户名查询用户信息
SysUser sysUser = sysUserDao.selectOne(new QueryWrapper<SysUser>()
.eq("user_name", username));
if (Objects.isNull(sysUser)) {
throw new RuntimeException("用户名或密码错误");
}
// 从数据库中获取权限列表
List<String> list = new ArrayList<>;
list.add("USER1");
// list.add("USER2");
// 返回用户信息 和 权限集合
return new LoginUser(sysUser, list);
}
}
在 JwtAuthenticationTokenFilter 中修改如下代码
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {
@Resource
private RedisCache redisCache;
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
//......
//存入SecurityContextHolder
//TODO 获取权限信息封装到Authentication中
UsernamePasswordAuthenticationToken authenticationToken =
new UsernamePasswordAuthenticationToken(loginUser,null,loginUser.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(authenticationToken);
//放行
filterChain.doFilter(request, response);
}
}
分别调用接口运行测试
@RestController
@RequestMapping("/user")
public class SysUserController {
@Resource
private SysUserService sysUserService;
// 登录方法......
// 退出登录......
@GetMapping("/list")
@PreAuthorize("hasAuthority('USER1')")
public ResultJSON list() {
return ResultJSON.success();
}
}
@RestController
@RequestMapping("/order")
public class SysOrderController {
@GetMapping("/list")
@PreAuthorize("hasAuthority('USER2')")
public ResultJSON list() {
return ResultJSON.success();
}
}
从数据库查询权限信息
RBAC 权限模型(Role-Based Access Control)
基于角色的权限控制。这是目前最常被开发者使用也是相对易用、通用权限模型。