1 RABC 是什么?
rabc 是一种用于设计权限的一种思想,流程图如下
2 硬编码实现的思想
RABC 主要有user 用户表,role角色表,permission权限表,以及role-permission和user-role的中间关联表,但是实际上对于一般的需求,我们可以只使用user用户表, 里面存储字段标识 角色信息,然后在代码层面进行编码方式 使用enum枚举出所有角色表,使用 权限注解标识方法,将权限注解与方法进行一个绑定,其中权限里面包括(角色)信息,通过拦截器进行拦截权限进行筛选。
- 权限注解
/**
* rbac 将角色存储到内存里
* 权限拦截
*/
@LoginRequired
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE,ElementType.METHOD})
public @interface PermissionRequired {
/**
* 角色
*/
UserType[] userType() default {UserType.VISITOR};
/**
* 逻辑关系,比如 ADMIN&&TEACHER 或者 ADMIN||TEACHER
*
* @return
*/
Logical logical();
}
- 用户角色枚举
/**
* 用户角色枚举
*/
@Getter
public enum UserType {
ADMIN(1,"管理员"),
TEACHER(2, "教师"),
STUDENT(3, "学生"),
VISITOR(4, "游客");
private final Integer value;
private final String desc;
UserType(Integer value,String desc){
this.value = value;
this.desc = desc;
}
public static boolean hasPermission(UserType[] userTypes,Integer typeOfUser,Logical logical){
Objects.requireNonNull(userTypes);
Objects.requireNonNull(logical);
// 单角色判断
if(userTypes.length==1 && userTypes[0].getValue().equals(typeOfUser)){
return true;
}
// 1.2 要求多个角色权限
if (userTypes.length > 1) {
// AND:预留,当前设计其实不支持一个用户有多个角色
if (Logical.AND.equals(logical)) {
return false;
}
// OR:只要用户拥有其中一个角色即可
if (Logical.OR.equals(logical)) {
for (UserType type : userTypes) {
if (type.getValue().equals(typeOfUser)) {
return true;
}
}
}
}
return false;
}
}
- 拦截
public class SecurityInterceptor extends HandlerInterceptorAdapter {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
// 不拦截跨域请求相关
if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
return true;
}
// 如果方法上没有加@LoginRequired或@PermissionRequired(上面叠加了@LoginRequired),直接放行
if (isLoginFree(handler)) {
return true;
}
// 登录校验
User user = handleLogin(request, response);
ThreadLocalUtil.put(WebConstant.USER_INFO, user);
// 权限校验
checkPermission(user, handler);
// 放行到Controller
return super.preHandle(request, response, handler);
}
- 使用
@PermissionRequired(userType = {UserType.ADMIN,UserType.TEACHER}, logical = Logical.OR)
@GetMapping("/needPermission")
public Result<String> needPermission() {
return Result.success("if you see this, you has the permission.");
}
缺点: 硬编码 将角色与权限进行的硬编码绑定,无法进行动态修改权限
3 动态实现
在数据库 中创建 五张表
- user 用户表
用户表 - role角色表,
每个用户都有自己的角色,通过角色进行权限的关联 - permission权限表
将方法资源作为自己的权限 - role-permission
角色-权限资源 - user-role
用户-角色资源