原子指令授权
原子指令授权
主要解决这类问题:谁
能对哪个范围内
的原子数据
执行什么操作
- 授权策略
CabloyJS采用白名单策略
,所有角色的授权都必须显式设置(superuser
也不例外)
- 授权内容
针对原子类型
的原子指令
授权,如以下授权记录:
角色 | 原子类型 | 原子指令 |
---|---|---|
system | party | create |
- 数据范围
在授权时可以指定权限的数据范围
,在CabloyJS中数据范围也是角色
,如以下授权记录
角色 | 原子类型 | 原子指令 | 数据范围 |
---|---|---|---|
system | party | read | 财务部 |
角色
system
仅能读取财务部
创建的party
数据
财务部
也是角色
授权途径
授权途径有三种:人工授权
、初始授权
、测试授权
- 人工授权
如果某些权限只有在实际部署或运行时才能决定,可通过管理界面
进行授权操作
- 初始授权
如果需要在系统运行时,预先初始化权限,可以在Bean组件version.manager
的方法init
中通过代码分配权限。比如,给模版角色system
分配权限
初始授权
在测试环境
、开发环境
和生产环境
均有效
src/suite-vendor/test-party/modules/test-party/backend/src/bean/version.manager.js
- 1async init(options) {
- 2 // only in test/local
- 3 if (!app.meta.isTest && !app.meta.isLocal) return;
- 4
- 5 // init
- 6 if (options.version === 1) {
- 7 // types
- 8 for (const name of [ 'Birthday', 'Dance', 'Garden' ]) {
- 9 await this.ctx.model.partyType.insert({ name });
- 10 }
- 11 // add role rights
- 12 const roleRights = [
- 13 // basic
- 14 { roleName: 'system', action: 'create' },
- 15 { roleName: 'system', action: 'read', scopeNames: 'authenticated' },
- 16 { roleName: 'system', action: 'write', scopeNames: 0 },
- 17 { roleName: 'system', action: 'delete', scopeNames: 0 },
- 18 { roleName: 'system', action: 'clone', scopeNames: 0 },
- 19 { roleName: 'system', action: 'deleteBulk' },
- 20 { roleName: 'system', action: 'exportBulk' },
- 21 ];
- 22 await this.ctx.bean.role.addRoleRightBatch({ atomClassName: 'party', roleRights });
- 23 }
- 24
- 25}
- 测试授权
为了测试与开发的便利,还可以在开发阶段
预先初始化权限,可以在Bean组件version.manager
的方法test
中通过代码分配权限。比如,给某些测试角色分配权限
测试授权
仅在测试环境
和开发环境
有效
src/suite-vendor/test-party/modules/test-party/backend/src/bean/version.manager.js
- 1const VersionTestFn = require('./version/test.js');
- 2
- 3async test() {
- 4 const versionTest = new (VersionTestFn(this.ctx))();
- 5 await versionTest.run();
- 6}
授权API
- addRoleRight
src/module-system/a-base-sync/backend/src/bean/bean.role/bean.role_atomRights.js
- 1async addRoleRight({ roleId, atomClassId, action, scope })
名称 | 说明 |
---|---|
roleId | 需要被授权的角色Id |
atomClassId | 原子类型Id |
action | 需要授权的指令code |
scope | 数据范围 |
scope支持以下值:
0
: 操作自己创建的原子数据roleId
: 操作roleId
及以下所有子角色的用户创建的原子数据roleIds
: roleId数组
- addRoleRightBatch
src/module-system/a-base-sync/backend/src/bean/bean.role/bean.role_atomRights.js
- 1async addRoleRightBatch({ module, atomClassName, roleRights })
名称 | 说明 |
---|---|
module | 模块名称,如果为空就使用当前模块名称 |
atomClassName | 原子类型名称 |
roleRights | 授权记录数组 |
授权判断方式
可以通过中间件
或Api
进行授权的判断
- 中间件判断
CabloyJS使用中间件right
封装了授权判断的逻辑,只需在后端路由上配置相应的中间件参数即可
src/suite-vendor/test-party/modules/test-party/backend/src/routes.js
- 1 {
- 2 method: 'post',
- 3 path: 'test/atom/checkRightCreate',
- 4 controller: 'testAtomRight',
- 5 middlewares: 'test',
- 6 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'create' } },
- 7 },
- 8 {
- 9 method: 'post',
- 10 path: 'test/atom/checkRightRead',
- 11 controller: 'testAtomRight',
- 12 middlewares: 'test',
- 13 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'read' } },
- 14 },
- 15 {
- 16 method: 'post',
- 17 path: 'test/atom/checkRightWrite',
- 18 controller: 'testAtomRight',
- 19 middlewares: 'test',
- 20 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'write' } },
- 21 },
- 22 {
- 23 method: 'post',
- 24 path: 'test/atom/checkRightAction',
- 25 controller: 'testAtomRight',
- 26 middlewares: 'test',
- 27 meta: { right: { type: 'atom', atomClass: 'test-party:party', action: 'partyOver' } },
- 28 },
名称 | 说明 |
---|---|
right | 全局中间件right ,默认处于开启状态,只需配置参数即可 |
type | 授权类型,这里是原子 授权 |
atomClass | 原子类型 |
action | 原子指令 |
- Api判断
src/suite-vendor/test-party/modules/test-party/backend/src/controller/test/atom/all.js
- 1// atomClass
- 2const atomClass = await this.ctx.bean.atomClass.get({ atomClassName: 'party' });
- 3// userIds
- 4const userIds = this.ctx.cache.mem.get('userIds');
1. 指令create
- 1const checkRightCreates = [[ 'Tom', true ], [ 'Jimmy', true ], [ 'Smith', false ]];
- 2for (const [ userName, right ] of checkRightCreates) {
- 3 const res = await this.ctx.bean.atom.checkRightCreate({
- 4 atomClass,
- 5 user: { id: userIds[userName] },
- 6 });
- 7 assert.equal(!!res, right, userName);
- 8}
2. 指令read
- 1const checkRightReads = [[ 'Tom', partyKey.atomId, true ]];
- 2for (const [ userName, atomId, right ] of checkRightReads) {
- 3 const res = await this.ctx.bean.atom.checkRightRead({
- 4 atom: { id: atomId },
- 5 user: { id: userIds[userName] },
- 6 });
- 7 assert.equal(!!res, right, userName);
- 8}
3. 指令write
- 1const checkRightWrites = [[ 'Tom', partyKeyFormal.atomId, true ], [ 'Tomson', partyKeyFormal.atomId, false ]];
- 2for (const [ userName, atomId, right ] of checkRightWrites) {
- 3 const res = await this.ctx.bean.atom.checkRightAction({
- 4 atom: { id: atomId },
- 5 action: 'write',
- 6 user: { id: userIds[userName] },
- 7 });
- 8 assert.equal(!!res, right, userName);
- 9}
4. 指令delete
- 1const checkRightDeletes = [[ 'Tom', partyKeyFormal.atomId, true ], [ 'Tomson', partyKeyFormal.atomId, false ]];
- 2for (const [ userName, atomId, right ] of checkRightDeletes) {
- 3 const res = await this.ctx.bean.atom.checkRightAction({
- 4 atom: { id: atomId },
- 5 action: 'delete',
- 6 user: { id: userIds[userName] },
- 7 });
- 8 assert.equal(!!res, right, userName);
- 9}
评论: