* 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', () => {
let acl: ACL;
beforeEach(() => {
acl = new ACL();
});
@ -25,7 +26,11 @@ describe('acl', () => {
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', () => {
@ -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 () {
acl.setAvailableAction('create', {
displayName: 'create',
@ -101,7 +111,11 @@ describe('acl', () => {
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', () => {
@ -121,8 +135,16 @@ describe('acl', () => {
strategy: 's1',
});
expect(acl.can({ role: 'admin', resource: 'posts', action: 'get' })).not.toBeNull();
expect(acl.can({ role: 'admin', resource: 'posts', action: 'list' })).not.toBeNull();
expect(acl.can({ role: 'admin', resource: 'posts', action: 'get' })).toMatchObject({
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', () => {
@ -210,7 +232,11 @@ describe('acl', () => {
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');

View File

@ -1,7 +1,9 @@
import lodash from 'lodash';
import { ACL } from './acl';
type StrategyValue = false | '*' | string | string[];
export interface AvailableStrategyOptions {
acl: ACL;
displayName?: string;
actions: false | string | string[];
resource?: '*';
@ -35,6 +37,6 @@ export class ACLAvailableStrategy {
}
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) {
return this.actions.get(name);
return this.actions.get(this.acl.resolveActionAlias(name));
}
setAction(name: string, params: RoleActionParams) {

View File

@ -75,8 +75,14 @@ export class ACL extends EventEmitter {
}
}
setAvailableStrategy(name: string, options: AvailableStrategyOptions) {
this.availableStrategy.set(name, new ACLAvailableStrategy(options));
setAvailableStrategy(name: string, options: Omit<AvailableStrategyOptions, 'acl'>) {
this.availableStrategy.set(
name,
new ACLAvailableStrategy({
...options,
acl: this,
}),
);
}
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 {
action = this.resolveActionAlias(action);
if (!this.isAvailableAction(action)) {
return null;
}
@ -94,15 +98,15 @@ export class ACL extends EventEmitter {
const aclResource = aclRole.getResource(resource);
if (aclResource) {
const aclActionConfig = aclResource.actions.get(this.resolveActionAlias(action));
const actionParams = aclResource.getAction(action);
if (aclActionConfig) {
if (actionParams) {
// handle single action config
return {
role,
resource,
action,
params: aclActionConfig,
params: actionParams,
};
}
}
@ -115,7 +119,7 @@ export class ACL extends EventEmitter {
return null;
}
if (roleStrategy.allow(resource, action)) {
if (roleStrategy.allow(resource, this.resolveActionAlias(action))) {
return { role, resource, action };
}
@ -123,10 +127,10 @@ export class ACL extends EventEmitter {
}
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;
}
}