Skip to main content

访问控制

ReactGO 提供基于角色和菜单码的访问控制,这种方式简单清晰,也足够应对大部分的情况, 如果你的系统需要更精细多变的访问控制,那么可以实现自己的访问控制,例如使用 OPA 编写访问规则。

概念

┌────────┐                          ┌─────────────┐
│ User A ├─────► ┌─────────┐ ┌►│ Menu 1 │
└────────┘ ┌► │ Role A ├──────┘ └─────────────┘
│ └─────────┤
┌────────┐ │ └───────►┌─────────────┐
│ User B ├────┘ ┌─────────┐ │ Menu 2 │
└────────┘ │ Role B ├─────┐ └─────────────┘
└─────────┘ │
┌────────┐ ▲ │ ┌─────────────┐
│ User C ├───────────┘ └► │ Menu 3 │
└────────┘ └─────────────┘

用户和角色

每个用户可以关联一个角色,也只能关联一个角色,角色用来确定最终的访问权限。 角色本身只是一堆菜单访问权限的集合,如果它没有分配给用户,那么它本身没有任何意义。

角色和菜单

角色是菜单的权限集合,一个角色可以包含 0 到多个菜单的访问权限。所谓菜单,对应的就是某个具体的 url,例如'用户管理'菜单的 url 是 /system/user,一般我们说菜单的时候,不会说 url,因为 url 只是实现细节,访问控制与 url 的关系不是很大,而是通过菜单代码来控制。

菜单和代码

每个菜单用一个代码来完成访问控制,例如“用户管理”的菜单代码是 9000,如果一个菜单没有代码, 那么就不能使用 ReactGO 内置的访问控制功能。菜单在 route/sidebar/codes.js 文件中定义。

保留菜单代码

菜单代码由 3 到 4 个数字构成,8000 以上的区域以及 911 是保留给系统的,不要使用。 你应该尽可能的使用 3 个数字菜单代码,因为更容易记忆。

菜单权限

每个菜单可以定义 3 个权限,管理,也可以说是 访问修改管理, 意思是一样的。

定义上,读是最基本的权限,如果没有读权限,那么基本上只能看见菜单,但是打开的话得不到任何数据, 也不能做任何操作。 有读权限后,可以访问数据,但是要修改数据,就需要写权限。 管理权限属于一种模糊权限,没有明确的定义,你可以根据自己的业务来适当的使用这个权限。

所有上面的 3 个权限,只是一种预设的定义,怎么使用完全在于你,参考后端访问控制部分。

前端访问控制

前端访问控制主要设计到几个部分:

  1. 菜单代码定义;
  2. 角色控制配置;
  3. 用户关联角色;

其中 2, 3 都已经内置,你无需做任何工作,你需要做的是 1。

访问控制

举个例子,假设你要新增一个业务办理的页面,你希望这个页面能够纳入访问控制, 那么你需要为这个业务定义一个菜单,在 src/route/sidebar/codes.js 文件中增加一行:

urlCodes = {
...

1111: { title: '业务办理', to: '/yewu' },

...
}

这行的意思是说,增加了一个菜单,代码为 1111,标题是业务办理,增加这行之后,如果你访问 访问控制 菜单,你会发现这个菜单可以纳入访问控制了。

配置好前端的访问控制后,如果用户现在访问 /yewu(假设你已经写好了页面), 即使用户没有分配访问权限,也照样可以访问,这是为什么呢?这是因为真正执行权限检查是在后端, 后端现在还没有增加访问控制。

顺便提一下,菜单代码不仅仅用于访问控制,同时也用于快速导航,就是你按下 Ctrl + K 时输入的那个数字。

后端访问控制

后端是真正执行访问控制检查的地方,主要是用三个函数: acl.AllowRead(code)acl.AllowWrite(code),以及 acl.AllowAdmin(code)

菜单代码

参数 code 对应前端定义的菜单代码,除了你知道这个代码的含义外,系统其他地方都不会去检查, 这非常的宽松,同时也意味着如果你写错了 code,系统是不会有任何提示的。 如果要修改菜单代码,记得前后端都要修改,如果你的菜单非常多,那么需要花点时间来设计菜单代码, 最好写在纸上。

这三个函数是中间件函数,可以这样用(用在组上):

group := up.Group("/task", acl.AllowRead(1111))

这样整个"组"都需要 1111 的 READ 权限才能访问。

也可以这样用(用在部分路由上):

// 这里不需要 WRITE 权限即可访问
// ...

group.Use(acl.AllowWrite(1111))

// 后续的访问需要 WRITE 权限才能访问
// ...

还可以这样用(用在单个路由上):

group.POST("/admin", Proc, acl.AllowAdmin(1111))

这个的意思是只针对 /admin 这个路由实施 ADMIN 权限控制。

中间键函数

可能你对这行语句有点疑惑:

group.POST("/admin", Proc, acl.AllowAdmin(code))

虽然看起来 acl.AllowAdmin() 写在 Proc 的后面,但实际上 acl.AllowAdmin() 会在 Proc 之前执行。

但是对于 Use() 就不一样了,Use() 只会影响它之后的路由,正如它的文档所说的那样:

Use adds middleware to the chain which is run after router.

更多信息请参考 Echo 文档。