diff --git a/README.md b/README.md index 9de9e91..4c7eb3e 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ async function myFunction() { await e.loadPolicy(); // Check the permission. - e.enforce('alice', 'data1', 'read'); + await e.enforce('alice', 'data1', 'read'); // Modify the policy. // await e.addPolicy(...); @@ -70,6 +70,46 @@ async function myFunction() { } ``` +## Simple Filter Example + +```typescript +import { newEnforcer } from 'casbin'; +import TypeORMAdapter from 'typeorm-adapter'; + +async function myFunction() { + // Initialize a TypeORM adapter and use it in a Node-Casbin enforcer: + // The adapter can not automatically create database. + // But the adapter will automatically and use the table named "casbin_rule". + // I think ORM should not automatically create databases. + const a = await TypeORMAdapter.newAdapter({ + type: 'mysql', + host: 'localhost', + port: 3306, + username: 'root', + password: '', + database: 'casbin', + }); + + + const e = await newEnforcer('examples/rbac_model.conf', a); + + // Load the filtered policy from DB. + await e.loadFilteredPolicy({ + 'ptype': 'p', + 'v0': 'alice' + }); + + // Check the permission. + await e.enforce('alice', 'data1', 'read'); + + // Modify the policy. + // await e.addPolicy(...); + // await e.removePolicy(...); + + // Save the policy back to DB. + await e.savePolicy(); +} +``` ## Getting Help - [Node-Casbin](https://github.com/casbin/node-casbin) diff --git a/src/adapter.ts b/src/adapter.ts index 71e1a76..b3cb6a2 100644 --- a/src/adapter.ts +++ b/src/adapter.ts @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -import {Adapter, Helper, Model} from 'casbin'; +import {Helper, Model, FilteredAdapter} from 'casbin'; import {CasbinRule} from './casbinRule'; import {Connection, ConnectionOptions, createConnection, getRepository, getConnection} from 'typeorm'; import {CasbinMongoRule} from './casbinMongoRule'; @@ -21,16 +21,21 @@ type GenericCasbinRule = CasbinRule | CasbinMongoRule; type CasbinRuleConstructor = new (...args: any[]) => GenericCasbinRule; /** - * TypeORMAdapter represents the TypeORM adapter for policy storage. + * TypeORMAdapter represents the TypeORM filtered adapter for policy storage. */ -export default class TypeORMAdapter implements Adapter { +export default class TypeORMAdapter implements FilteredAdapter { private option: ConnectionOptions; private typeorm: Connection; + private filtered = false; private constructor(option: ConnectionOptions) { this.option = option; } + public isFiltered(): boolean { + return this.filtered; + } + /** * newAdapter is the constructor. * @param option typeorm connection option @@ -80,6 +85,15 @@ export default class TypeORMAdapter implements Adapter { } } + // Loading policies based on filter condition + public async loadFilteredPolicy(model: Model, filter: object) { + const filteredLines = await getRepository(this.getCasbinRuleConstructor(), this.option.name).find(filter); + for (const line of filteredLines) { + this.loadPolicyLine(line, model); + } + this.filtered = true; + } + private savePolicyLine(ptype: string, rule: string[]): GenericCasbinRule { const line = new (this.getCasbinRuleConstructor())(); diff --git a/test/adapter.test.ts b/test/adapter.test.ts index 63d5ae2..40a744f 100644 --- a/test/adapter.test.ts +++ b/test/adapter.test.ts @@ -22,6 +22,11 @@ function testGetPolicy(e: Enforcer, res: string[][]) { expect(Util.array2DEquals(res, myRes)).toBe(true); } +function testGetFilteredPolicy(e: Enforcer, res: string[]) { + const myRes = e.getFilteredNamedPolicy('p', 0, 'alice')[0]; + expect(Util.arrayEquals(res, myRes)).toBe(true); +} + test('TestAdapter', async () => { const a = await TypeORMAdapter.newAdapter({ type: 'mysql', @@ -66,6 +71,10 @@ test('TestAdapter', async () => { ['data2_admin', 'data2', 'read'], ['data2_admin', 'data2', 'write']]); + // load filtered policies + await a.loadFilteredPolicy(e.getModel(), { ptype: 'p', v0: 'alice'}); + testGetFilteredPolicy(e, ['alice', 'data1', 'read']); + // Add policy to DB await a.addPolicy('', 'p', ['role', 'res', 'action']); e = await Enforcer.newEnforcer('examples/rbac_model.conf', a);