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
    用户-角色资源

更多推荐