原子授权

原子授权主要解决这类问题:能对哪个范围内原子数据执行什么操作

授权内容

针对原子类型原子指令授权,如以下授权记录:

角色 原子类型 原子指令
system party create

资源范围

在授权时可以指定权限的资源范围,如以下授权记录

角色 原子类型 原子指令 资源范围
system party read 财务部

角色system仅能读取财务部创建的party数据

授权途径

授权途径有三种:人工授权初始授权测试授权

这里重点说明CabloyJS为初始授权测试授权提供的API方法

addRoleRight

a-base/backend/src/config/middleware/adapter/role.js

async addRoleRight({ roleId, atomClassId, action, scope })
名称 说明
roleId 需要被授权的角色Id
atomClassId 原子类型Id
action 需要授权的指令code
scope 资源范围

scope支持以下值:

  • 0: 操作自己创建的原子数据
  • roleId: 操作roleId及以下所有子角色的用户创建的原子数据
  • roleIds: roleId数组

addRoleRightBatch

a-base/backend/src/config/middleware/adapter/role.js

// const roleRights = [
//   { roleName: 'cms-writer', action: 'create' },
//   { roleName: 'cms-writer', action: 'write', scopeNames: 0 },
//   { roleName: 'cms-writer', action: 'delete', scopeNames: 0 },
//   { roleName: 'cms-writer', action: 'read', scopeNames: 'authenticated' },
//   { roleName: 'cms-publisher', action: 'read', scopeNames: 'authenticated' },
//   { roleName: 'cms-publisher', action: 'write', scopeNames: 'authenticated' },
//   { roleName: 'cms-publisher', action: 'publish', scopeNames: 'authenticated' },
//   { roleName: 'root', action: 'read', scopeNames: 'authenticated' },
// ];
async addRoleRightBatch({ module, atomClassName, atomClassIdParent = 0, roleRights })
名称 说明
module 模块名称,如果为空就使用当前模块名称
atomClassName 原子类型名称
roleRights 授权记录数组

举例

src/module/test-party/backend/src/service/version.js

// add role rights
const roleRights = [
  { roleName: 'system', action: 'create' },
  { roleName: 'system', action: 'write', scopeNames: 0 },
  { roleName: 'system', action: 'delete', scopeNames: 0 },
  { roleName: 'system', action: 'read', scopeNames: 'authenticated' },
  { roleName: 'system', action: 'review', scopeNames: 'authenticated' },
];
await this.ctx.meta.role.addRoleRightBatch({ atomClassName: 'party', roleRights });

授权判断一览表

由于原子提供了许多特性,草稿简单流程公开访问等状态都会影响对原子授权的判断

原子不同状态对应的授权判断清单如下

指令 草稿 简单流程 公开访问 正常
create - - - -
read 只有创建人有权限 判断是否有其他指令的授权,比如有write权限必然有read权限 不需判断 需判断
write、delete 只有创建人有权限 需判断 - 需判断
扩展指令 - 需判断 - 需判断
  • -: 不支持
  • create: 只需对原子类型授权,与原子的状态无关

草稿

原子有两个状态:草稿正常

草稿状态下,只有创建人自己可以执行修改删除指令

正常状态下,只有拥有授权的用户才可以执行相应授权的指令。即便是创建人,如果没有赋予授权,也不能执行writedelete等指令

公开访问

默认情况下,原子只有被授予了权限才可以被查询到。CabloyJS同样也支持不授予权限而直接公开访问,只需将原子类型的public属性设为1即可

简单流程

CabloyJS目前实现了原子的简单流程处理

比如,我们可以设计这样一种流程:

1、用户新建文章,此时处于草稿状态,只能自己查看

2、用户提交文章,此时仍不能公开访问,但是拥有review授权的审核员可以查看

3、审核员review之后,文章才允许公开访问

授权判断方式

可以通过中间件Api进行授权的判断

中间件判断

CabloyJS使用中间件right封装了授权判断的逻辑,只需在后端路由上配置相应的中间件参数即可

src/module/test-party/backend/src/routes.js

{ method: 'post', path: 'test/atom/checkRightCreate', controller: testAtomRight, middlewares: 'test',
  meta: { right: { type: 'atom', action: 1 } },
},
{ method: 'post', path: 'test/atom/checkRightRead', controller: testAtomRight, middlewares: 'test',
  meta: { right: { type: 'atom', action: 2 } },
},
{ method: 'post', path: 'test/atom/checkRightWrite', controller: testAtomRight, middlewares: 'test',
  meta: { right: { type: 'atom', action: 3 } },
},
{ method: 'post', path: 'test/atom/checkRightAction', controller: testAtomRight, middlewares: 'test',
  meta: { right: { type: 'atom', action: 101 } },
},
名称 说明
right 全局中间件right,默认处于开启状态,只需配置参数即可
type 授权类型,这里是原子授权
action 原子指令代码

Api判断

src/module/test-party/backend/src/controller/test/atom/all.js

// atomClass
const atomClass = await this.ctx.meta.atomClass.get({ atomClassName: 'party' });
// userIds
const userIds = this.ctx.cache.mem.get('userIds');

指令create

const checkRightCreates = [[ 'Tom', true ], [ 'Jimmy', true ], [ 'Smith', false ]];
for (const [ userName, right ] of checkRightCreates) {
  const res = await this.ctx.meta.atom.checkRightCreate({
    atomClass,
    user: { id: userIds[userName] },
  });
  assert.equal(!!res, right, userName);
}

指令read

const checkRightReads = [[ 'Tom', partyKey.atomId, true ]];
for (const [ userName, atomId, right ] of checkRightReads) {
  const res = await this.ctx.meta.atom.checkRightRead({
    atom: { id: atomId },
    user: { id: userIds[userName] },
  });
  assert.equal(!!res, right, userName);
}

指令write

const checkRightWrites = [[ 'Tom', partyKey.atomId, true ], [ 'Tomson', partyKey.atomId, false ]];
for (const [ userName, atomId, right ] of checkRightWrites) {
  const res = await this.ctx.meta.atom.checkRightUpdate({
    atom: { id: atomId, action: this.ctx.constant.module('a-base').atom.action.write },
    user: { id: userIds[userName] },
  });
  assert.equal(!!res, right, userName);
}

指令delete

const checkRightDeletes = [[ 'Tom', partyKey.atomId, true ], [ 'Tomson', partyKey.atomId, false ]];
for (const [ userName, atomId, right ] of checkRightDeletes) {
  const res = await this.ctx.meta.atom.checkRightUpdate({
    atom: { id: atomId, action: this.ctx.constant.module('a-base').atom.action.delete },
    user: { id: userIds[userName] },
  });
  assert.equal(!!res, right, userName);
}

扩展指令

// action: review(101)
const checkRightActions_1 = [[ 'Tom', partyKey.atomId, false ], [ 'Jane', partyKey.atomId, true ]];
for (const [ userName, atomId, right ] of checkRightActions_1) {
  const res = await this.ctx.meta.atom.checkRightAction({
    atom: { id: atomId, action: 101 },
    user: { id: userIds[userName] },
  });
  assert.equal(!!res, right, userName);
}