feat: app.acl support
This commit is contained in:
parent
a2037d90c9
commit
ffbf4ecb66
@ -1,5 +1,7 @@
|
||||
export * from './acl';
|
||||
export * from './acl-available-action';
|
||||
export * from './acl-available-strategy';
|
||||
export * from './acl-resource';
|
||||
export * from './acl-role';
|
||||
export * from './acl-available-strategy';
|
||||
export * from './acl-available-action';
|
||||
export * from './acl';
|
||||
export * from './skip-middleware';
|
||||
|
||||
|
16
packages/acl/src/skip-middleware.ts
Normal file
16
packages/acl/src/skip-middleware.ts
Normal file
@ -0,0 +1,16 @@
|
||||
export const skip = (options: ACLSkipOptions) => {
|
||||
return async function ACLSkipMiddleware(ctx, next) {
|
||||
const { resourceName, actionName } = ctx.action;
|
||||
if (resourceName === options.resourceName && actionName === options.actionName) {
|
||||
ctx.permission = {
|
||||
skip: true,
|
||||
};
|
||||
}
|
||||
await next();
|
||||
};
|
||||
};
|
||||
|
||||
interface ACLSkipOptions {
|
||||
resourceName: string;
|
||||
actionName: string;
|
||||
}
|
@ -1,8 +1,7 @@
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { Database } from '@nocobase/database';
|
||||
import { MockServer } from '@nocobase/test';
|
||||
import { prepareApp } from './prepare';
|
||||
import { Database } from '@nocobase/database';
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import PluginACL from '../server';
|
||||
|
||||
describe('acl', () => {
|
||||
let app: MockServer;
|
||||
@ -16,9 +15,7 @@ describe('acl', () => {
|
||||
beforeEach(async () => {
|
||||
app = await prepareApp();
|
||||
db = app.db;
|
||||
const aclPlugin = app.getPlugin<PluginACL>('PluginACL');
|
||||
|
||||
acl = aclPlugin.getACL();
|
||||
acl = app.acl;
|
||||
});
|
||||
|
||||
it('should works with universal actions', async () => {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { MockServer } from '@nocobase/test';
|
||||
import { Database, HasManyRepository, Model } from '@nocobase/database';
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { Database, HasManyRepository, Model } from '@nocobase/database';
|
||||
import { MockServer } from '@nocobase/test';
|
||||
import { prepareApp } from './prepare';
|
||||
import PluginACL from '@nocobase/plugin-acl';
|
||||
|
||||
describe('association field acl', () => {
|
||||
let app: MockServer;
|
||||
@ -18,9 +17,7 @@ describe('association field acl', () => {
|
||||
beforeEach(async () => {
|
||||
app = await prepareApp();
|
||||
db = app.db;
|
||||
const aclPlugin = app.getPlugin<PluginACL>('PluginACL');
|
||||
|
||||
acl = aclPlugin.getACL();
|
||||
acl = app.acl;
|
||||
|
||||
role = await db.getRepository('roles').create({
|
||||
values: {
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { Database, Model } from '@nocobase/database';
|
||||
import { MockServer } from '@nocobase/test';
|
||||
import { changeMockUser, prepareApp } from './prepare';
|
||||
import { Database, Model } from '@nocobase/database';
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import PluginACL from '@nocobase/plugin-acl';
|
||||
|
||||
describe('middleware', () => {
|
||||
let app: MockServer;
|
||||
@ -13,7 +12,7 @@ describe('middleware', () => {
|
||||
beforeEach(async () => {
|
||||
app = await prepareApp();
|
||||
db = app.db;
|
||||
acl = app.getPlugin<PluginACL>('PluginACL').getACL();
|
||||
acl = app.acl;
|
||||
|
||||
await db.getRepository('roles').create({
|
||||
values: {
|
||||
|
@ -1,13 +1,12 @@
|
||||
import PluginACL from '..';
|
||||
|
||||
const availableActionResource = {
|
||||
name: 'availableActions',
|
||||
actions: {
|
||||
list(ctx, next) {
|
||||
const aclPlugin: PluginACL = ctx.app.getPlugin('PluginACL');
|
||||
const acl = aclPlugin.getACL();
|
||||
async list(ctx, next) {
|
||||
const acl = ctx.app.acl;
|
||||
const availableActions = acl.getAvailableActions();
|
||||
ctx.body = Array.from(availableActions.entries()).map((item) => item[1]);
|
||||
await next();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -32,6 +32,8 @@ const roleCollectionsResource = {
|
||||
usingConfig,
|
||||
};
|
||||
});
|
||||
|
||||
await next();
|
||||
},
|
||||
},
|
||||
};
|
||||
|
@ -1,7 +1,5 @@
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import path from 'path';
|
||||
import { createACL } from './acl';
|
||||
import { resolve } from 'path';
|
||||
import { availableActionResource } from './actions/available-actions';
|
||||
import { roleCollectionsResource } from './actions/role-collections';
|
||||
import { RoleResourceActionModel } from './model/RoleResourceActionModel';
|
||||
@ -28,18 +26,17 @@ export class GrantHelper {
|
||||
}
|
||||
|
||||
export class PluginACL extends Plugin {
|
||||
acl: ACL;
|
||||
|
||||
associationFieldsActions: AssociationFieldsActions = {};
|
||||
|
||||
grantHelper = new GrantHelper();
|
||||
|
||||
registerAssociationFieldAction(associationType: string, value: AssociationFieldActions) {
|
||||
this.associationFieldsActions[associationType] = value;
|
||||
get acl() {
|
||||
return this.app.acl;
|
||||
}
|
||||
|
||||
getACL() {
|
||||
return this.acl;
|
||||
registerAssociationFieldAction(associationType: string, value: AssociationFieldActions) {
|
||||
this.associationFieldsActions[associationType] = value;
|
||||
}
|
||||
|
||||
registerAssociationFieldsActions() {
|
||||
@ -104,11 +101,6 @@ export class PluginACL extends Plugin {
|
||||
}
|
||||
|
||||
async beforeLoad() {
|
||||
const acl = createACL();
|
||||
this.acl = acl;
|
||||
|
||||
// @ts-ignore
|
||||
this.app.acl = acl;
|
||||
|
||||
this.app.db.registerModels({
|
||||
RoleResourceActionModel,
|
||||
@ -123,10 +115,10 @@ export class PluginACL extends Plugin {
|
||||
this.app.db.on('roles.afterSave', async (model, options) => {
|
||||
const { transaction } = options;
|
||||
const roleName = model.get('name');
|
||||
let role = acl.getRole(roleName);
|
||||
let role = this.acl.getRole(roleName);
|
||||
|
||||
if (!role) {
|
||||
role = acl.define({
|
||||
role = this.acl.define({
|
||||
role: model.get('name'),
|
||||
});
|
||||
}
|
||||
@ -153,7 +145,7 @@ export class PluginACL extends Plugin {
|
||||
|
||||
this.app.db.on('roles.afterDestroy', (model) => {
|
||||
const roleName = model.get('name');
|
||||
acl.removeRole(roleName);
|
||||
this.acl.removeRole(roleName);
|
||||
});
|
||||
|
||||
this.app.db.on('rolesResources.afterSaveWithAssociations', async (model: RoleResourceModel, options) => {
|
||||
@ -241,7 +233,7 @@ export class PluginACL extends Plugin {
|
||||
|
||||
async load() {
|
||||
await this.app.db.import({
|
||||
directory: path.resolve(__dirname, 'collections'),
|
||||
directory: resolve(__dirname, 'collections'),
|
||||
});
|
||||
|
||||
this.app.resourcer.use(this.acl.middleware());
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { skip } from '@nocobase/acl';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
|
||||
export class ClientPlugin extends Plugin {
|
||||
@ -18,17 +19,12 @@ export class ClientPlugin extends Plugin {
|
||||
}
|
||||
|
||||
async load() {
|
||||
// @ts-ignore
|
||||
this.app.acl.use(async (ctx, next) => {
|
||||
const { resourceName } = ctx.action;
|
||||
if (resourceName === 'app') {
|
||||
ctx.permission = {
|
||||
skip: true,
|
||||
};
|
||||
}
|
||||
await next();
|
||||
});
|
||||
|
||||
this.app.acl.use(
|
||||
skip({
|
||||
resourceName: 'app',
|
||||
actionName: 'getLang',
|
||||
}),
|
||||
);
|
||||
this.app.resource({
|
||||
name: 'app',
|
||||
actions: {
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { skip } from '@nocobase/acl';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import { resolve } from 'path';
|
||||
|
||||
@ -23,6 +24,12 @@ export class SystemSettingsPlugin extends Plugin {
|
||||
await this.app.db.import({
|
||||
directory: resolve(__dirname, 'collections'),
|
||||
});
|
||||
this.app.acl.use(
|
||||
skip({
|
||||
resourceName: 'systemSettings',
|
||||
actionName: 'get',
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
import { skip } from '@nocobase/acl';
|
||||
import { MagicAttributeModel } from '@nocobase/database';
|
||||
import { Plugin } from '@nocobase/server';
|
||||
import { resolve } from 'path';
|
||||
@ -130,6 +131,12 @@ export class UiRoutesStoragePlugin extends Plugin {
|
||||
this.app.db.import({
|
||||
directory: resolve(__dirname, 'collections'),
|
||||
});
|
||||
this.app.acl.use(
|
||||
skip({
|
||||
resourceName: 'uiRoutes',
|
||||
actionName: 'getAccessible',
|
||||
}),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -12,6 +12,7 @@
|
||||
"dependencies": {
|
||||
"@koa/cors": "^3.1.0",
|
||||
"@koa/router": "^9.4.0",
|
||||
"@nocobase/acl": "0.6.0-alpha.0",
|
||||
"@nocobase/actions": "^0.6.0-alpha.0",
|
||||
"@nocobase/database": "^0.6.0-alpha.0",
|
||||
"@nocobase/resourcer": "^0.6.0-alpha.0",
|
||||
|
@ -4,24 +4,28 @@ const availableActions: {
|
||||
[key: string]: AvailableActionOptions;
|
||||
} = {
|
||||
create: {
|
||||
displayName: 't("create")',
|
||||
displayName: 't("Create")',
|
||||
type: 'new-data',
|
||||
},
|
||||
import: {
|
||||
displayName: 't("import")',
|
||||
displayName: 't("Import")',
|
||||
type: 'new-data',
|
||||
},
|
||||
export: {
|
||||
displayName: 't("Import")',
|
||||
type: 'new-data',
|
||||
},
|
||||
view: {
|
||||
displayName: 't("view")',
|
||||
displayName: 't("View")',
|
||||
type: 'old-data',
|
||||
aliases: ['get', 'list'],
|
||||
},
|
||||
update: {
|
||||
displayName: 't("edit")',
|
||||
displayName: 't("Edit")',
|
||||
type: 'old-data',
|
||||
},
|
||||
destroy: {
|
||||
displayName: 't("destroy")',
|
||||
displayName: 't("Delete")',
|
||||
type: 'old-data',
|
||||
},
|
||||
};
|
@ -1,3 +1,4 @@
|
||||
import { ACL } from '@nocobase/acl';
|
||||
import { registerActions } from '@nocobase/actions';
|
||||
import Database, { CleanOptions, CollectionOptions, DatabaseOptions, SyncOptions } from '@nocobase/database';
|
||||
import Resourcer, { ResourceOptions } from '@nocobase/resourcer';
|
||||
@ -7,6 +8,7 @@ import { Server } from 'http';
|
||||
import { i18n, InitOptions } from 'i18next';
|
||||
import Koa from 'koa';
|
||||
import { isBoolean } from 'lodash';
|
||||
import { createACL } from './acl';
|
||||
import { createCli, createDatabase, createI18n, createResourcer, registerMiddlewares } from './helper';
|
||||
import { Plugin } from './plugin';
|
||||
import { PluginManager } from './plugin-manager';
|
||||
@ -86,6 +88,8 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
|
||||
public readonly pm: PluginManager;
|
||||
|
||||
public readonly acl: ACL;
|
||||
|
||||
protected plugins = new Map<string, Plugin>();
|
||||
|
||||
public listenServer: Server;
|
||||
@ -93,6 +97,7 @@ export class Application<StateT = DefaultState, ContextT = DefaultContext> exten
|
||||
constructor(options: ApplicationOptions) {
|
||||
super();
|
||||
|
||||
this.acl = createACL();
|
||||
this.db = createDatabase(options);
|
||||
this.resourcer = createResourcer(options);
|
||||
this.cli = createCli(this, options);
|
||||
|
Loading…
Reference in New Issue
Block a user