权限控制RABC 96

224 阅读4分钟

概念

RBAC(Role-Based Access Control )基于角色的访问控制。

RBAC认为权限的过程可以抽象概括为:判断【Who是否可以对What进行How的访问操作(Operator)】这个逻辑表达式的值是否为True的求解过程。

3、RBAC96是一个模型族,其中包括RBAC0~RBAC3四个概念性模型。

1、)基本模型RBAC0定义了完全支持RBAC概念的任何系统的最低需求。

2、)RBAC1和RBAC2两者都包含RBAC0,但各自都增加了独立的特点,它们被称为高级模型。

    RBAC1中增加了角色分级的概念,一个角色可以从另一个角色继承许可权。

    RBAC2中增加了一些限制,强调在RBAC的不同组件中在配置方面的一些限制。

3、)RBAC3称为统一模型,它包含了RBAC1和RBAC2,利用传递性,也把RBAC0包括在内。

代码示例


/**
 * 操作权限校验
 * @param userId        用户id                      Who
 
  @param documentId    知识库id、目录id、文档id      what
 * @param operationEnum 操作类型                     How
 * 
 *
 */
public void checkOperationAuthority(OperationEnum operationEnum, String userId, String documentId) {
    switch (operationEnum) {
        // 1. 知识库所有者或管理员有权限
        case DC_LIBRARY_ADD:
            // 新增知识库目录、文档
        case DC_LIBRARY_RENAME:
            // 重命名
        case READ_NOTIFY_SETTING:
            // 查看提醒
        case DC_LIBRARY_DOCUMENT_SAVE:
            // 保存文档
            checkRoleOwnerOrAdmin(userId, documentId);
            break;

        // 2. 所有者有权限
        case DC_LIBRARY_SETTING:
            // 知识库设置
        case MEMBER:
            // 知识库人员设置
        case SHARE_SETTING:
            // 分享
            checkRoleOwner(userId, documentId);
            break;

        // 3. 自定义权限判断
        case DC_LIBRARY_DEL:
            // 删除知识库(知识库、目录、文档)权限校验
            delDcLibraryRole(userId, documentId);
            break;
        default:
            throw new BusinessException("无权操作");
    }
}



/**
 * 权限校验——知识库“拥有者” 或 “管理员”有权操作
 *
 * @param userId     用户id
 * @param documentId 知识库id(可以是知识库id、目录id、文档id。最终都会以知识库id查询权限)
 */
private void checkRoleOwnerOrAdmin(String userId, String documentId) {
    DcLibraryUser dcLibraryUser = getUserRole(userId, documentId);
    boolean flag = dcLibraryUser == null ||
            (!DcLibraryUserRoleEnum.owner.equals(dcLibraryUser.getRole()) && !DcLibraryUserRoleEnum.admin.equals(dcLibraryUser.getRole()));
    if (flag) {
        throw new BusinessException("知识库所有者或管理员有权操作");
    }
}
 

/**
 * 查询用户知识库权限
 *
 * @param userId     用户id
 * @param documentId 知识库id(可以是知识库id、目录id、文档id。最终都会以知识库id查询权限)
 */
private DcLibraryUser getUserRole(String userId, String documentId) {
    if (StringUtils.isBlank(userId) && StringUtils.isBlank(documentId)) {
        log.error("权限校验入参为空:userId:{}, documentId: {}", userId, documentId);
        throw new BusinessException("无权操作");
    }
    // 查询知识库
    DcLibrary dcLibrary = dcLibraryService.getKnowledgeByChildren(documentId);
    if (dcLibrary == null) {
        throw new BusinessException("知识库不存在");
    }
    // 拥有者才有权限
    return dcLibraryUserService.getOne(Wrappers.<DcLibraryUser>lambdaQuery()
            .eq(DcLibraryUser::getUserId, userId)
            .eq(DcLibraryUser::getDcLibraryId, dcLibrary.getId())
            .select(DcLibraryUser::getRole));
}



@Data
@Accessors(chain = true)
@AllArgsConstructor
@NoArgsConstructor
@ApiModel("知识库-文档对应的用户")
@EqualsAndHashCode(callSuper = false)
@TableName("dc_library_user")
public class DcLibraryUser extends BasalPo implements Serializable {
    private static final long serialVersionUID = 1L;

    @ApiModelProperty("id")
    @TableId(value = "id", type = IdType.ASSIGN_UUID)
    private String id;
    @ApiModelProperty("用户ID")
    private String userId;
    @ApiModelProperty("用户名")
    private String realName;
    @ApiModelProperty("知识库的ID值")
    private String dcLibraryId;
    @ApiModelProperty(" 权限/所有者、管理员、成员")
    private DcLibraryUserRoleEnum role;
    @ApiModelProperty("是否删除 0未删除  1已删除")
    @TableLogic
    private Boolean delFlag;

    @ApiModelProperty("备注")
    @TableField("remark")
    private String remark;

    @ApiModelProperty("租户")
    @TableField("tenant_id")
    private String tenantId;

}

@Getter
public enum DcLibraryUserRoleEnum {
    /**
     * 所有者、、
     */
    owner("owner","owner"),
    /**
     * 管理员
     **/
    admin("admin","admin"),
    /**
     * 成员
     **/
    member("member","member"),
    ;
    @EnumValue
    public final String value;
    public final String desc;

    DcLibraryUserRoleEnum(String value, String desc) {
        this.value = value;
        this.desc = desc;
    }
}


、RBAC 权限体系设计

1、用户-角色-权限

RBAC0模式,包含了2种:

  1. 用户和角色是多对一关系,即:一个用户只充当一种角色,一种角色可以有多个用户担当;
  2. 用户和角色是多对多关系,即:一个用户可同时充当好几种角色,一种角色可以有多个用户担当;

权限体系,尽量可能地使用多对多的权限体系。

2、用户-组织-角色-权限

在“用户-角色-权限”的基础上,我们增加了用户与组织的关联关系,组织决定了用户的数据可视权限。但要想真正达到这个效果,我们还需要做2件事:

  1. 组织层级划分。
  2. 数据可视权限规则制定。比如:上级组织职能看到下级组织员工负责的数据,而不能看到其他平级组织及其下级组织的员工数据等。

通过以上两点,系统就可以在用户登录时,自动判断给用户展示哪些数据。

3、用户-组织-岗位-角色-权限

第三种权限体系又是在第二种权限体系上进行优化的,增加了用户与岗位的关联关系,示意图如下:

增加岗位有以下几点好处:

  1. 识别用户的主要身份。
  2. 一个人可能身兼多职(多个角色),但是他的主要职能是固定的,系统用户的主要职能 可以通过岗位区分。