UNPKG

egg-rbac-plugin

Version:

egg的rbac插件

578 lines (538 loc) 18.3 kB
'use strict'; const path = require('path'); const fs = require('fs'); const debug = require('debug')('egg-rbac-plugin'); const mongooseStorage = require('./mongoose/index'); class rbac { /** * @constructs role * @param {object} app eggjs application object */ constructor(app) { this.mongooseConfig = app.config.mongoose; this.config = app.config.rbac; this.storage = new mongooseStorage(app); if (app.config.rbac.initOnStart) { app.beforeStart(() => { const appRbacFilePath = path.join(app.baseDir, 'config/rbac.js'); debug('app rbac config file path %s file path exit %s ', appRbacFilePath, fs.existsSync(appRbacFilePath)); if (fs.existsSync(appRbacFilePath)) { const data = require(appRbacFilePath); return this.initData(data.permissions, data.roles, data.groups); } }); } } /** * before start init permissions and roles and groups * @method rbac#initData * @param {object[]} permissions - permission item array * @param {string} permissions[].name - permission name * @param {string} permissions[].alias - permission alias * @param {object[]} roles - role item array * @param {string} roles[].name - role name * @param {string} roles[].alias - role alias * @param {object[]} groups - group item array * @param {string} groups[].name - group name * @param {string} groups[].alias - group alias * @return {object} error object * @yields {boolean} */ initData(permissions, roles, groups) { if (!permissions || permissions.length === 0) { throw new Error('[egg-rbac-plugin] initData parameter permissions is undefined'); } if (!roles || roles.length === 0) { throw new Error('[egg-rbac-plugin] initData parameter roles is undefined'); } if (!groups || groups.length === 0) { throw new Error('[egg-rbac-plugin] initData parameter groups is undefined'); } debug('init data permissions.length %O roles.length %O groups.length %O', permissions.length, roles.length, groups.length); return this._initPermissions(permissions) .then(() => this._initRole(roles)) .then(() => this._initGroup(groups)); } /** * Initialize permission * @method rbac#_initPermissions * @private * @param {object[]} permissions - permission item array * @param {string} permissions[].name - permission name * @param {string} permissions[].alias - permission alias * @return {string[]|null} null or ObjectId array */ _initPermissions(permissions) { debug('init permission permission type is %s', typeof permissions); return this.getAllPermissions() .then(oldPermission => { const oldPermissionObj = {}; oldPermission.forEach(item => { oldPermissionObj[item.name] = item; }); permissions = permissions.filter(item => { if (oldPermissionObj[item.name]) { return false; } return true; }); if (permissions.length === 0) { return []; } return this.storage.insertManyPermission(permissions); }); } /** * Initialize roles * @method rbac#_initRole * @private * @param {object[]} roles - role item array * @param {string} roles[].name - role name * @param {string} roles[].alias - role alias * @return {object} promise */ _initRole(roles) { const arr = roles.map(roleData => { return Promise.all([ this.storage.getPermissionsByNames(roleData.permissions).then(permissions => permissions.map(per => per._id)), this.storage.getRoleByName(roleData.name), ]).then(([ ids, role ]) => { debug('init role %s ', role); if (role === null) { roleData.permissions = ids; return this.newRole(roleData); } return this.addPermission(role._id, ids); }); }); return Promise.all(arr); } /** * Initialize groups * @method rbac#_initGroup * @private * @param {object[]} groups - groups item array * @param {string} groups[].name - groups name * @param {string} groups[].alias - groups alias * @return {object} promise */ _initGroup(groups) { const arr = groups.map(groupData => { return Promise.all([ this.storage.getRolesByNames(groupData.roles).then(roles => roles.map(per => per._id)), this.storage.getGroupByName(groupData.name), ]).then(([ ids, group ]) => { debug('init role %s ', group); if (group === null) { groupData.roles = ids; return this.newGroup(groupData); } return this.addRole(group._id, ids); }); }); return Promise.all(arr); } /** * @method rbac#newRole * @param {object} options role info * @param {string} options.name - role short name * @param {string} options.alias - role full name such as chinese name * @param {string[]} options.permissions - string such as mongodb ObjectId * @return {object} promise */ newRole({ name, alias, permissions }) { if (!name) { return new Error('[egg-rbac-plugin] newRole parameter name is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] newRole parameter alias is undefined'); } debug('new role name %s alias %s', name, alias); return this.storage.newRole({ name, alias, permissions }); } /** * @method rbac#newGroup * @param {object} options role info * @param {string} options.name - role short name * @param {string} options.alias - role full name such as chinese name * @param {string[]} options.roles - string such as mongodb ObjectId * @return {object} promise */ newGroup({ name, alias, roles }) { if (!name) { return new Error('[egg-rbac-plugin] newGroup parameter name is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] newGroup parameter alias is undefined'); } debug('new role name %s alias %s', name, alias); return this.storage.newGroup({ name, alias, roles }); } /** * @method rbac#newPermission * @param {object} options role info * @param {string} options.name - permission short name * @param {string} options.alias - permission full name such as chinese name * @param {String} options.category - category of permission short name * @param {String} options.categoryAlias - category of permission full name such as chinese name * @return {object} promise */ newPermission({ name, alias, category, categoryAlias }) { if (!name) { return new Error('[egg-rbac-plugin] newPermission parameter name is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] newPermission parameter alias is undefined'); } if (!category) { return new Error('[egg-rbac-plugin] newPermission parameter category is undefined'); } if (!categoryAlias) { return new Error('[egg-rbac-plugin] newPermission parameter categoryAlias is undefined'); } debug('new permission name %s alias %s category %s categoryAlias %s', name, alias, category, categoryAlias); return this.storage.newPermission({ name, alias, category, categoryAlias }); } /** * @method rbac#addPermission * @param {string} _id - role id * @param {string[]} permissionIds - permission ids * @return {object} promise */ addPermission(_id, permissionIds) { if (!_id) { return new Error('[egg-rbac-plugin] addPermission parameter _id is undefined'); } if (!permissionIds || typeof permissionIds !== 'object' || permissionIds.length === 0) { return new Error('[egg-rbac-plugin] addPermission parameter permissionIds is undefined'); } debug('new permission name %s alias %s', _id, permissionIds); return this.storage.addPermission(_id, permissionIds); } /** * @method rbac#addRole * @param {string} _id - group id * @param {string[]} roleIds - role ids * @return {object} promise */ addRole(_id, roleIds) { if (!_id) { return new Error('[egg-rbac-plugin] addRole parameter _id is undefined'); } if (!roleIds || typeof roleIds !== 'object' || roleIds.length === 0) { return new Error('[egg-rbac-plugin] addPermission parameter roleIds is undefined'); } debug('new permission name %s alias %s', _id, roleIds); return this.storage.addRole(_id, roleIds); } /** * @method rbac#removeRolePermissions * @param {string} _id - role id * @param {string[]} permissionIds - permission ids * @return {object} promise */ removeRolePermissions(_id, permissionIds) { if (!_id) { return new Error('[egg-rbac-plugin] removeRolePermissions parameter _id is undefined'); } if (!permissionIds || typeof permissionIds !== 'object' || permissionIds.length === 0) { return new Error('[egg-rbac-plugin] removeRolePermissions parameter permissionIds is undefined'); } debug('new permission name %s alias %s', _id, permissionIds); return this.storage.removeRolePermissions(_id, permissionIds); } /** * @method rbac#removeGroupRoles * @param {string} _id - role id * @param {string[]} roleIds - role ids * @return {object} promise */ removeGroupRoles(_id, roleIds) { if (!_id) { return new Error('[egg-rbac-plugin] removeGroupRoles parameter _id is undefined'); } if (!roleIds || typeof roleIds !== 'object' || roleIds.length === 0) { return new Error('[egg-rbac-plugin] removeGroupRoles parameter roleIds is undefined'); } debug('new permission name %s alias %s', _id, roleIds); return this.storage.removeGroupRoles(_id, roleIds); } /** * @method rbac#removeGroup * @param {string} _id - role _id * @return {object} promise */ removeGroup(_id) { if (!_id) { return new Error('[egg-rbac-plugin] removeGroup parameter _id is undefined'); } return this.storage.removeGroup(_id); } /** * @method rbac#removeRole * @param {string} _id - role _id * @return {object} promise */ removeRole(_id) { if (!_id) { return new Error('[egg-rbac-plugin] removeRole parameter _id is undefined'); } return this.storage.removeRole(_id); } /** * @method rbac#removePermission * @param {string} _id - permission _id * @return {object} promise */ removePermission(_id) { if (!_id) { return new Error('[egg-rbac-plugin] removePermission parameter _id is undefined'); } return this.storage.removePermission(_id); } /** * @method rbac#modifyRoleAlias * @param {string} _id - role _id * @param {string} alias - new alias string * @return {object} promise */ modifyRoleAlias(_id, alias) { if (!_id) { return new Error('[egg-rbac-plugin] modifyRoleAlias parameter _id is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] modifyRoleAlias parameter alias is undefined'); } return this.storage.modifyRoleAlias(_id, alias); } /** * @method rbac#modifyGroupAlias * @param {string} _id - role _id * @param {string} alias - new alias string * @return {object} promise */ modifyGroupAlias(_id, alias) { if (!_id) { return new Error('[egg-rbac-plugin] modifyGroupAlias parameter _id is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] modifyGroupAlias parameter alias is undefined'); } return this.storage.modifyGroupAlias(_id, alias); } /** * @method rbac#modifyPermissionAlias * @param {string} _id - role _id * @param {string} alias - new alias string * @return {object} promise */ modifyPermissionAlias(_id, alias) { if (!_id) { return new Error('[egg-rbac-plugin] modifyPermissionAlias parameter _id is undefined'); } if (!alias) { return new Error('[egg-rbac-plugin] modifyPermissionAlias parameter alias is undefined'); } return this.storage.modifyPermissionAlias(_id, alias); } /** * @method rbac#modifyPermissionCategory * @param {string} _id - role _id * @param {string} category - new category string * @param {string} categoryAlias - new categoryAlias string * @return {object} promise */ modifyPermissionCategory(_id, category, categoryAlias) { if (!_id) { return new Error('[egg-rbac-plugin] modifyPermissionCategory parameter _id is undefined'); } if (!category) { return new Error('[egg-rbac-plugin] modifyPermissionCategory parameter category is undefined'); } if (!categoryAlias) { return new Error('[egg-rbac-plugin] modifyPermissionCategory parameter categoryAlias is undefined'); } return this.storage.modifyPermissionCategory(_id, category, categoryAlias); } /** * @method rbac#getRolePermission * @param {string} name - role name * @return {object} promise */ getRolePermission(name) { if (!name || typeof name !== 'string') { return new Error('[egg-rbac-plugin] getRolePermission parameter name must string'); } debug('get role permission role name is %s', name); return this.storage.getRoleByName(name) .then(role => role.permissions); } /** * @method rbac#getGroupPermission * @param {string} name - group name * @return {object} promise */ getGroupPermission(name) { if (!name || typeof name !== 'string') { return new Error('[egg-rbac-plugin] getGroupPermission parameter name must string'); } debug('get group permission group name is %s', name); return this.storage.getGroupPermission(name); } /** * @method rbac#getAllPermissions * @return {object} promise */ getAllPermissions() { return this.storage.getAllPermissions(); } /** * @method rbac#getPermissionsByQuery * @param {object} query * @param {object} option * @return {object} promise */ getPermissionsByQuery(query, option) { return this.storage.getPermissionsByQuery(query, option); } /** * @method rbac#getPermissionsTotal * @param {} query query * @return {object} promise */ getPermissionsTotal(query) { return this.storage.getPermissionsTotal(query? query: {}); } /** * @method rbac#getAllPermissionsGroupByCategory * @return {object} promise */ getAllPermissionsGroupByCategory(style) { return this.storage.getAllPermissionsGroupByCategory(style); } /** * @method rbac#getRoleByName * @param {string} name role name * @return {object} promise */ getRoleByName(name) { if (!name || typeof name !== 'string') { return new Error('[egg-rbac-plugin] getRoleByName parameter name must string'); } return this.storage.getRoleByName(name); } /** * @method rbac#getAllRoles * @return {object} promise */ getAllRoles() { return this.storage.getAllRoles(); } /** * @method rbac#getRolesByQuery * @param {object} query * @param {object} option * @return {object} promise */ getRolesByQuery(query, option) { return this.storage.getRolesByQuery(query, option); } /** * @method rbac#getRolesTotal * @param {} query query * @return {object} promise */ getRolesTotal(query) { return this.storage.getRolesTotal(query? query: {}); } /** * @method rbac#getGroupByName * @param {string} name group name * @return {object} promise */ getGroupByName(name) { if (!name || typeof name !== 'string') { return new Error('[egg-rbac-plugin] getGroupByName parameter name must string'); } return this.storage.getGroupByName(name); } /** * @method rbac#getAllRoles * @return {object} promise */ getAllGroups() { return this.storage.getAllGroups(); } /** * @method rbac#getGroupsByQuery * @param {object} query * @param {object} option * @return {object} promise */ getGroupsByQuery(query, option) { return this.storage.getGroupsByQuery(query, option); } /** * @method rbac#getGroupsTotal * @param {} query query * @return {object} promise */ getGroupsTotal(query) { return this.storage.getGroupsTotal(query? query: {}); } /** * @method rbac#can * @param {string} permissionName - permission name * @return {function} middleware function */ can(permissionName) { return async function(ctx, next) { // this is instance of Context if (ctx.group && ctx.group.can && ctx.group.can(permissionName)) { await next(); } else { // https://tools.ietf.org/html/rfc2616#page-66 ctx.status = 401; // 'Unauthorized' } }; } /** * @method rbac#canAny * @param {string[]} permissionNames - permission names * @return {function} middleware function */ canAny(permissionNames) { return async function(ctx, next) { // this is instance of Context if (ctx.group && ctx.group.canAny && ctx.group.canAny(permissionNames)) { await next(); } else { // https://tools.ietf.org/html/rfc2616#page-66 ctx.status = 401; // 'Unauthorized' } }; } /** * @method rbac#canAll * @param {string[]} permissionNames - permission names * @return {function} middleware function */ canAll(permissionNames) { return async function(ctx, next) { // this is instance of Context if (ctx.group && ctx.group.canAll && ctx.group.canAll(permissionNames)) { await next(); } else { // https://tools.ietf.org/html/rfc2616#page-66 ctx.status = 401; // 'Unauthorized' } }; } } let singleton = null; module.exports = exports = function(app) { if (singleton === null) { singleton = new rbac(app); } return singleton; };