* feat: getRepository

* getRepository return type

* export action

* add: acl

* feat: setResourceAction

* feat: action alias

* chore: code struct

* feat: removeResourceAction

* chore: file name

* ignorecase

* remove ACL

* feat: ACL

* feat: role toJSON

* using emit

* chore: test

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
ChengLei Shao 2022-01-18 20:29:41 +08:00 committed by GitHub
parent fd32705954
commit 43f33044ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 50 additions and 18 deletions

View File

@ -2,6 +2,7 @@ import { ACL } from '..';
describe('acl', () => { describe('acl', () => {
let acl: ACL; let acl: ACL;
beforeEach(() => { beforeEach(() => {
acl = new ACL(); acl = new ACL();
}); });
@ -25,7 +26,11 @@ describe('acl', () => {
strategy: 's1', strategy: 's1',
}); });
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).not.toBeNull(); expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
}); });
it('should deny all', () => { it('should deny all', () => {
@ -79,8 +84,13 @@ describe('acl', () => {
}, },
}); });
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).not.toBeNull(); expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
}); });
it('should grant action', function () { it('should grant action', function () {
acl.setAvailableAction('create', { acl.setAvailableAction('create', {
displayName: 'create', displayName: 'create',
@ -101,7 +111,11 @@ describe('acl', () => {
role.grantAction('posts:create', {}); role.grantAction('posts:create', {});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).not.toBeNull(); expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
}); });
it('should works with alias action', () => { it('should works with alias action', () => {
@ -121,8 +135,16 @@ describe('acl', () => {
strategy: 's1', strategy: 's1',
}); });
expect(acl.can({ role: 'admin', resource: 'posts', action: 'get' })).not.toBeNull(); expect(acl.can({ role: 'admin', resource: 'posts', action: 'get' })).toMatchObject({
expect(acl.can({ role: 'admin', resource: 'posts', action: 'list' })).not.toBeNull(); role: 'admin',
resource: 'posts',
action: 'get',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'list' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'list',
});
}); });
it('should return action params when check permission', () => { it('should return action params when check permission', () => {
@ -210,7 +232,11 @@ describe('acl', () => {
role.grantAction('posts:create', {}); role.grantAction('posts:create', {});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).not.toBeNull(); expect(acl.can({ role: 'admin', resource: 'posts', action: 'create' })).toMatchObject({
role: 'admin',
resource: 'posts',
action: 'create',
});
role.revokeAction('posts:create'); role.revokeAction('posts:create');

View File

@ -1,7 +1,9 @@
import lodash from 'lodash'; import lodash from 'lodash';
import { ACL } from './acl';
type StrategyValue = false | '*' | string | string[]; type StrategyValue = false | '*' | string | string[];
export interface AvailableStrategyOptions { export interface AvailableStrategyOptions {
acl: ACL;
displayName?: string; displayName?: string;
actions: false | string | string[]; actions: false | string | string[];
resource?: '*'; resource?: '*';
@ -35,6 +37,6 @@ export class ACLAvailableStrategy {
} }
allow(resourceName: string, actionName: string) { allow(resourceName: string, actionName: string) {
return this.matchAction(actionName); return this.matchAction(this.options.acl.resolveActionAlias(actionName));
} }
} }

View File

@ -35,7 +35,7 @@ export class ACLResource {
} }
getAction(name: string) { getAction(name: string) {
return this.actions.get(name); return this.actions.get(this.acl.resolveActionAlias(name));
} }
setAction(name: string, params: RoleActionParams) { setAction(name: string, params: RoleActionParams) {

View File

@ -75,8 +75,14 @@ export class ACL extends EventEmitter {
} }
} }
setAvailableStrategy(name: string, options: AvailableStrategyOptions) { setAvailableStrategy(name: string, options: Omit<AvailableStrategyOptions, 'acl'>) {
this.availableStrategy.set(name, new ACLAvailableStrategy(options)); this.availableStrategy.set(
name,
new ACLAvailableStrategy({
...options,
acl: this,
}),
);
} }
beforeGrantAction(path: string, listener?: Listener) { beforeGrantAction(path: string, listener?: Listener) {
@ -84,8 +90,6 @@ export class ACL extends EventEmitter {
} }
can({ role, resource, action }: { role: string; resource: string; action: string }): CanResult | null { can({ role, resource, action }: { role: string; resource: string; action: string }): CanResult | null {
action = this.resolveActionAlias(action);
if (!this.isAvailableAction(action)) { if (!this.isAvailableAction(action)) {
return null; return null;
} }
@ -94,15 +98,15 @@ export class ACL extends EventEmitter {
const aclResource = aclRole.getResource(resource); const aclResource = aclRole.getResource(resource);
if (aclResource) { if (aclResource) {
const aclActionConfig = aclResource.actions.get(this.resolveActionAlias(action)); const actionParams = aclResource.getAction(action);
if (aclActionConfig) { if (actionParams) {
// handle single action config // handle single action config
return { return {
role, role,
resource, resource,
action, action,
params: aclActionConfig, params: actionParams,
}; };
} }
} }
@ -115,7 +119,7 @@ export class ACL extends EventEmitter {
return null; return null;
} }
if (roleStrategy.allow(resource, action)) { if (roleStrategy.allow(resource, this.resolveActionAlias(action))) {
return { role, resource, action }; return { role, resource, action };
} }
@ -123,10 +127,10 @@ export class ACL extends EventEmitter {
} }
protected isAvailableAction(actionName: string) { protected isAvailableAction(actionName: string) {
return this.availableActions.has(actionName); return this.availableActions.has(this.resolveActionAlias(actionName));
} }
protected resolveActionAlias(action: string) { public resolveActionAlias(action: string) {
return this.actionAlias.get(action) ? this.actionAlias.get(action) : action; return this.actionAlias.get(action) ? this.actionAlias.get(action) : action;
} }
} }