egg-rbac-plugin
Version:
egg的rbac插件
578 lines (538 loc) • 18.3 kB
JavaScript
'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;
};