跳到主要内容
版本:2.21

基于角色的权限控制

基于角色的权限控制(Role-Based Access Control,RBAC)是一种广泛应用的访问控制机制,旨在通过定义用户的角色来简化和增强权限管理。 在 Halo 中,RBAC 通过限制对系统资源的访问来确保系统的安全性和可管理性。

RBAC 的基本概念​

RBAC 通过三个核心概念来管理权限:

  1. 角色(Role) :角色定义了一组操作权限,这些操作可以包括对某些资源的“读”、“写”或“执行”等权限。在 Halo 中,角色可以绑定到用户,从而赋予它们相应的权限,同时角色可以依赖于其他角色,从而实现权限的继承以简化权限管理。

  2. 用户(User) :用户是实际使用 Halo 资源的实体。

  3. 角色绑定(RoleBinding) :角色绑定是将用户与特定的角色关联起来。通过角色绑定,某个用户可以获得与角色相关的权限。

通过上述三者的结合,RBAC 可以灵活地控制用户对 Halo 资源的访问权限。

什么是基于角色的权限控制​

RBAC 的核心思想是将权限分配给角色,而不是直接分配给用户。用户通过被分配一个或多个角色来获得相应的权限。每个角色都定义了可以执行的操作,如读取、写入、删除等操作。这种设计具有以下几个优点:

  1. 简化权限管理:管理员可以通过管理少数角色来控制大量用户的权限,而不需要为每个用户单独配置权限。
  2. 权限最小化:用户只会被赋予完成工作所需的最低权限,减少了安全风险。
  3. 易于扩展:新增用户或变更权限只需要调整角色,无需修改大量的用户配置。

Role 和 RoleBinding​

在 Halo 中,Role 是通过自定义模型来定义的。一个典型的 Role 的 YAML 配置如下:

apiVersion: v1alpha1
kind: Role
metadata:
name: example-role
rules:
- apiGroups: [""]
resources: ["menus"]
verbs: ["get", "list"]

上面的例子定义了一个名为 example-role 的角色。该角色允许用户对菜单资源执行 get 和 list 操作。

  • apiGroups 定义了资源所属的 API 组,"" 表示核心 API 组。
  • resources 是指定角色可以操作的资源类型。
  • verbs 表示可以执行的操作,比如 get、create、delete 等。

RoleBinding 与角色的关联​

定义好角色后,我们需要通过 RoleBinding 将其与某个用户关联,RoleBinding 绑定了 Role 并指定了哪些用户可以获得该角色的权限。 在 Halo 为用户分配角色也是通过 RoleBinding 来实现的。一个典型的 RoleBinding 的 YAML 配置如下:

apiVersion: v1alpha1
kind: RoleBinding
metadata:
name: fake-user-binding
subjects:
# 绑定的用户,这是一个数组,可以绑定多个用户
- kind: User
name: fake-user
apiGroup: ""
roleRef:
kind: Role
name: example-role
apiGroup: ""

角色模板​

虽然角色已经定义了一组操作权限,但是粒度太细的角色会导致权限管理复杂,如文章管理的角色可能需要包含了文章、分类、标签、用户等多个资源的操作权限才能提供完整的功能,而这些操作权限可能会被多个角色共享。 为了简化权限管理,Halo 提供了角色模板的功能,角色模板是一组操作权限的集合,可以被多个角色共享。同时,角色模板也可以继承其他角色模板,从而实现权限的继承。

创建角色模板​

角色模板是通过一个特殊的 label 来标识 Role 对象实现的,一个典型的角色模板的 YAML 配置如下:

apiVersion: v1alpha1
kind: Role
metadata:
name: example-role
labels:
# 通过 halo.run/role-template: "true" 标识为角色模板
halo.run/role-template: "true"
rules:
- apiGroups: [""]
resources: ["menus"]
verbs: ["get", "list"]

Halo 在用户界面只会显示非模板角色,这样可以避免用户误操作角色模板,同时也可以简化用户对角色的管理。 用户创建角色时通过选择角色模板来创建角色,角色模板在用户界面以权限的概念展示,比如文章管理、用户管理等。

继承角色/角色模板​

可以在角色的 annotations 中添加 rbac.authorization.halo.run/dependencies 来声明角色间的依赖关系,例如菜单管理必须要依赖菜单查看,以避免分配了管理权限却没有查看权限的情况。 当角色依赖于其他角色时,Halo 会自动将依赖的角色的权限合并到当前角色中以实现权限的继承。

apiVersion: v1alpha1
kind: Role
metadata:
name: example-role
labels:
halo.run/role-template: "true"
annotations:
rbac.authorization.halo.run/dependencies: |
[ "view-menu" ]
rules:
- apiGroups: [""]
resources: ["menus"]
verbs: [ "create", "update", "delete" ]
---
apiVersion: v1alpha1
kind: Role
metadata:
name: view-menu
labels:
halo.run/role-template: "true"
rules:
- apiGroups: [""]
resources: ["menus"]
verbs: ["get", "list"]

聚合角色​

角色定义依赖关系适合于定义角色模板时复用 rules 或者用户创建角色时绑定其他角色,但是如果想要将一个角色的权限合并到另一个已有的角色中(如 Halo 提供的),这种情况下角色依赖关系就无法满足需求了。 例如,当插件开发者想要将自己插件的角色权限合合并到 Halo 的角色中时,无法修改 Halo 的角色定义,这时可以通过聚合角色来实现。

聚合角色通过 rbac.authorization.halo.run/aggregate-to-{role-name} 的 labels 来声明,其中的 {role-name} 占位符表示要聚合到的角色名。

例如插件开发者想要将插件的某些 API 资源公开给所有人访问即不需要授权,可以通过将角色聚合到 anonymous 角色来实现。

apiVersion: v1alpha1
kind: Role
metadata:
name: template-moment-anonymous-resources
labels:
halo.run/role-template: "true"
rbac.authorization.halo.run/aggregate-to-anonymous: "true"
rules:
- apiGroups: ["api.moment.halo.run"]
resources: ["moments"]
verbs: ["get", "list"]

上述配置将 template-moment-anonymous-resources 角色聚合到 anonymous 角色中,用户无需登录即可访问 api.moment.halo.run 下的 moments 资源。

rbac.authorization.halo.run/aggregate-to-editor 表示将 role-template-view-categories 角色聚合到 editor 角色中,这样所有拥有 editor 角色的用户都会拥有 role-template-view-categories 角色的权限。

在 Halo 中,anonymous 角色是一个特殊的角色,表示未登录的匿名访客。

隐藏角色模板​

Halo 提供了隐藏角色模板的功能,隐藏的角色模板不会在用户界面的权限列表中显示,对于聚合角色来说,隐藏角色模板是非常有用的,它可以避免用户在权限列表中看到不应该看到的角色模板。

隐藏角色模板通过 halo.run/hidden: "true" 的 labels 来标识,它必须是一个角色模板。

apiVersion: v1alpha1
kind: Role
metadata:
name: template-moment-anonymous-resources
labels:
# 声明为角色模板
halo.run/role-template: "true"
# 声明为隐藏
halo.run/hidden: "true"
# 聚合到 anonymous 角色
rbac.authorization.halo.run/aggregate-to-anonymous: "true"
rules:
- apiGroups: ["api.moment.halo.run"]
resources: ["moments"]
verbs: ["get", "list"]

Halo 中的特殊角色​

anonymous 角色​

在 Halo 中,任何访问者都会被赋予一个特殊的角色,这个角色是 anonymous,表示未登录的匿名访客。anonymous 角色是一个特殊的角色,它不需要绑定到用户,用户无需登录即可获得 anonymous 角色的权限。

anonymous 角色的定义参考 anonymous 角色。

authenticated 角色​

authenticated 角色表示已登录的用户,用户登录后会被赋予 authenticated 角色。authenticated 角色的权限是 Halo 中所有用户的最小权限,即所有登录用户都会获得 authenticated 角色的权限。

如果开发插件时但凡登录用户都需要具备的权限集合,可以通过将角色聚合到 authenticated 角色来实现。这样便不需要为每个用户单独配置权限,只需要将角色聚合到 authenticated 角色即可。

authenticated 角色的定义参考 authenticated 角色。

Halo 中的内置角色​

Halo 中内置了一些角色,管理员可以在创建用户时直接分配这些角色。内置角色的权限是固定的,不可修改。

超级管理员​

超级管理员的角色名为 super-role,它包含了 Halo 中所有资源的所有权限。超级管理员可以访问 Halo 中的所有资源,包括系统资源和插件资源。

apiVersion: v1alpha1
kind: Role
metadata:
name: super-role
labels:
rbac.authorization.halo.run/system-reserved: "true"
annotations:
rbac.authorization.halo.run/display-name: "超级管理员"
rbac.authorization.halo.run/ui-permissions: |
["*"]
rules:
- apiGroups: ["*"]
resources: ["*"]
nonResourceURLs: ["*"]
verbs: ["*"]

访客角色​

访客角色的角色名为 guest,它没有任何权限,当用户被分配了访客角色时,用户只具有 anonymous 和 authenticated 角色的权限,由于 anonymous 和 authenticated 角色是不可分配的,因此访客角色用来表示用户的这种状态。

apiVersion: v1alpha1
kind: Role
metadata:
name: guest
labels:
rbac.authorization.halo.run/system-reserved: "true"
annotations:
rbac.authorization.halo.run/display-name: "访客"
rbac.authorization.halo.run/disallow-access-console: "true"
rules: []

文章内置角色​

文章是 Halo 的核心功能之一,因此 Halo 内置了一些文章相关的角色,以便个人中心功能的正常运行。

  • 文章作者:文章作者允许用户管理自己的文章,包括投稿、创建、修改、发布、删除等操作。
  • 投稿者:投稿者允许用户投稿文章,但是不能直接发布文章,需要管理员审核后才能发布。
  • 文章管理员:文章管理员允许用户管理所有文章,包括修改、发布、删除等文章关联的所有操作。

参考​

关于角色模板的配置详解请参考API 权限控制。