一. RABC介绍
RBAC【Role-based access control】,增加了角色的概念,即基于角色的访问控制,将权限分配给角 色,再将角色分配给用户。简单来说,就是【用户关联角色,角色关联权限】。
RBAC遵循三条安全原则:
最小权限原则:给角色配置最小但能满足使用需求的权限。
责任分离原则:给比较重要或者敏感的事件设置不同的角色,不同的角色间是相互约束的,由其一 同参与完成。
数据抽象原则:每个角色都只能访问其需要的数据,而不是全部数据,不同的角色能访问到的数据 也不同。
二、SpringSecurity 权限认证
SpringSecurity要求将身份认证信息存到GrantedAuthority对象列表中。代表了当前用户的权限。 GrantedAuthority对象由AuthenticationManager插入到Authentication对象中,然后在做出授权决策 时由AccessDecisionManager实例读取。
可以看到UserDetails中有个Collection<? extends GrantedAuthority> 方法,权限列表就是放在这个集合里面的;一个用户的权限是在用户登录的时候,获取用户的所有权限(具体逻辑代码可以通过自定义Service,实现UserDetailsService接口,并且实现loadUserByUsername方法,在这个方法里面通过查询数据库来获取用户的授权信息)。
自定义的实体类应该是怎样的??
@Data
@TableName("ums_sys_user")
public class UmsSysUser implements Serializable, UserDetails {
@TableId
private Long id;
private String username;
private String nickname;
private String email;
private Integer sex;
private String avatar;
private String password;
private Integer status;
private Long creator;
private Long updater;
private LocalDateTime createTime;
private LocalDateTime updateTime;
@TableLogic
private Integer deleted;
private String remark;
//角色信息
private Set<UmsRole> roleSet = new HashSet<>();
//授权信息
private Set<String> perms = new HashSet<>();
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
//将权限告知给SpringSecurity.通过lambda表达式将String转成set<G>
if(perms != null && perms.size() > 0){
//返回权限信息 set类型
return perms.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toSet());
}
return null;
}
@Override
public String getPassword() {
return password;
}
@Override
public String getUsername() {
return username;
}
@Override
public boolean isAccountNonExpired() {
return status == 0;
}
@Override
public boolean isAccountNonLocked() {
return status == 0;
}
@Override
public boolean isCredentialsNonExpired() {
return status == 0;
}
@Override
public boolean isEnabled() {
return status == 0;
}
}
实现UserDetails 接口,重写getAuthorities方法,可以加上一个属性,作为存放权限的容器,获取的时候直接返回这个集合即可,在loadUserByUsername中就可以这样写:
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("loadUserByUsername ==== > {}",username);
//1.查询角色信息
UmsSysUser umsSysUser = umsSysUserMapper.selectUserByUsername(username);
//2.查询权限信息
if(umsSysUser != null){
//角色集合
Set<UmsRole> roleSet = umsSysUser.getRoleSet();
//角色ID集合
HashSet<Long> roleIdSet = new HashSet<>(roleSet.size());
//获取用户的权限列表
for (UmsRole umsRole : roleSet) {
roleIdSet.add(umsRole.getRoleId());
}
// 用户权限列表
Set<String> perms = umsSysUser.getPerms();
//权限查询
Set<UmsMenu> umsMenus = menuMapper.selectMenuByRoleId(roleIdSet);
//把权限都放到perms集合中去。
for (UmsMenu umsMenu : umsMenus) {
perms.add(umsMenu.getPerms());
}
log.info("有权限 ========> {}",umsSysUser);
}
//返回一个用户信息,里面包括角色信息和权限信息。
return umsSysUser;
}