前端集成
Casbin.js 把 Casbin 风格的访问控制带到前端:定义权限(例如从后端获取),并用它们来显示/隐藏 UI 或为用户路由。它支持 manual(手动)模式(你在代码中设置权限)或 auto(自动)模式(从 API 获取权限)。
安装
npm install casbin.js
npm install casbin
或者
yarn add casbin.js
前端框架
| Framework | Type | Author | Description |
|---|---|---|---|
| react-authz | React | Casbin | Casbin.js 的 React 封装 |
| rbac-react | React | @daobeng | 在 React 中使用高阶组件、CASL 和 Casbin.js 实现的基于角色的访问控制 |
| vue-authz | Vue | Casbin | Casbin.js 的 Vue 封装 |
| angular-authz | Angular | Casbin | Casbin.js 的 Angular 封装 |
快速上手
把 Casbin.js 配置为 manual 模式,在前端应用中显式设置权限:
const casbinjs = require("casbin.js");
// Set the user's permission:
// He/She can read `data1` and `data2` objects and can write `data1` object
const permission = {
"read": ["data1", "data2"],
"write": ["data1"]
}
// Run casbin.js in manual mode, which requires you to set the permission manually.
const authorizer = new casbinjs.Authorizer("manual");
有了 authorizer 实例后,你可以使用 authorizer.can() 和 authorizer.cannot() 检查权限。这两个方法都返回 JavaScript Promise(参见 MDN 文档),因此请用 then() 方法处理结果:
result = authorizer.can("write", "data1");
result.then((success, failed) => {
if (success) {
console.log("you can write data1");
} else {
console.log("you cannot write data1");
}
});
// output: you can write data1
cannot() 方法的用法相同:
result = authorizer.cannot("read", "data2");
result.then((success, failed) => {
if (success) {
console.log("you cannot read data2");
} else {
console.log("you can read data2");
}
});
// output: you can read data2
success 参数表示查询没有出错,并不代表权限被授予。同样,failed 与查询错误相关,而不是权限被拒绝。
实际使用时可以参考我们的 React 示例。
权限对象
Casbin.js 使用一个 JSON 对象表示访问者的权限。例如:
{
"read": ["data1", "data2"],
"write": ["data1"]
}
该对象表示访问者可以读取 data1 和 data2 两个对象,但只能写入 data1。
进阶用法
Casbin.js 在前端访问控制与你的后端 Casbin 服务之间提供了无缝集成。
使用 auto 模式,并在初始化 Casbin.js 的 Authorizer 时指定后端端点。它会自动同步权限并管理前端授权状态:
const casbinjs = require('casbin.js');
// Set your backend Casbin service URL
const authorizer = new casbinjs.Authorizer(
'auto', // mode
{endpoint: 'http://your_endpoint/api/casbin'}
);
// Set your visitor.
// Casbin.js will automatically sync the permission with your backend Casbin service.
authorizer.setUser("Tom");
// Evaluate the permission
result = authorizer.can("read", "data1");
result.then((success, failed) => {
if (success) {
// Some frontend procedure ...
}
});
在后端,暴露一个端点(例如 REST API)为前端生成权限对象。在你的 API 控制器中,调用 CasbinJsGetUserPermission 来构造权限对象。下面这个 Beego 示例演示了这种模式:
你的端点应该返回类似这样的响应:
{
"other":"other",
"data": "What you get from `CasbinJsGetPermissionForUser`"
}
// Router
beego.Router("api/casbin", &controllers.APIController{}, "GET:GetFrontendPermission")
// Controller
func (c *APIController) GetFrontendPermission() {
// Get the visitor from the GET parameters. (The key is "casbin_subject")
visitor := c.Input().Get("casbin_subject")
// `e` is an initialized instance of Casbin Enforcer
c.Data["perm"] = casbin.CasbinJsGetPermissionForUser(e, visitor)
// Pass the data to the frontend.
c.ServeJSON()
}
目前,CasbinJsGetPermissionForUser 仅在 Go Casbin 和 Node-Casbin 中可用。如需在其他语言中支持,请提交 issue 或在下方留言。
API 参考
setPermission(permission: string)
设置权限对象。主要用于 manual 模式。
setUser(user: string)
设置访问者身份并刷新权限。主要用于 auto 模式。
can(action: string, object: string)
检查用户是否可以对 object 执行 action。
cannot(action: string, object: string)
检查用户是否不能对 object 执行 action。
canAll(action: string, objects: Array<object>)
检查用户是否可以对 objects 中的所有对象执行 action。
canAny(action: string, objects: Array<object>)
检查用户是否可以对 objects 中的任意对象执行 action。
为什么使用 Casbin.js
人们常会问 Node-Casbin 和 Casbin.js 有什么区别。Node-Casbin 是 Casbin 在 Node.js 环境下的核心实现,通常部署在服务端做访问控制管理。Casbin.js 则是一个前端库,帮助你在客户端为网页用户应用 Casbin 授权逻辑。
直接为前端授权搭建 Casbin 服务存在几个问题:
- 客户端连接时,enforcer 会初始化并从后端存储拉取全部 policy。高并发会给数据库带来压力,并消耗大量网络带宽。
- 把所有 policy 暴露给客户端会带来安全漏洞。
- 客户端与服务端紧密耦合会增加开发和维护成本。
Casbin.js 通过在客户端层面管理用户权限来解决这些问题。其核心功能是通过一次 fetch 操作,把当前用户的权限与后端 Casbin 服务同步。获取权限数据后,开发者就可以使用 Casbin.js 的接口在前端控制用户行为。
这种方式避免了重复初始化 enforcer,减小了客户端与服务端之间的消息体积,也避免了在前端暴露全部 policy。用户只能访问自己的权限,既不了解访问控制模型,也不知道其他用户的权限。此外,Casbin.js 还有效解耦了客户端与服务端的授权逻辑。