diff --git a/README.md b/README.md index b8cea7c..9ed9ccf 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,8 @@ We demonstrate the usage of Casbin.js with [a React app](https://github.com/casb You can use `manual` mode in Casbin.js, and set the permission whenever you wish. + +### Simple Permission Format ```javascript const casbinjs = require('casbin.js'); @@ -27,7 +29,7 @@ const permission = { // Run casbin.js in manual mode, which requires you to set the permission manually. const authorizer = new casbinjs.Authorizer("manual"); -authorizer.setPermission(permission); +await authorizer.setPermission(permission); authorizer.can("read", "data1").then(result => { console.log(result) @@ -37,6 +39,29 @@ authorizer.cannot("write", "data2").then(result => { }); ``` +### Using Enforcer Format from Go Backend +If you're using Go's `CasbinJsGetPermissionForUser` API, you can directly pass the result to `setPermission()` in manual mode. The library will automatically detect the enforcer format and handle it correctly. + +```javascript +const casbinjs = require('casbin.js'); + +// Get permission from your Go backend API +const responseFromApi = await fetch('http://your-api/casbin-permission').then(r => r.json()); + +const authorizer = new casbinjs.Authorizer("manual"); + +// Set permission with enforcer format (contains 'm' and 'p' keys) +await authorizer.setPermission(responseFromApi); + +// Set the current user +await authorizer.setUser("alice"); + +// Evaluate permissions +authorizer.can("read", "data1").then(result => { + console.log(result) +}); +``` + You can also use the `auto` mode. In details, specify a casbin backend service endpoint when initializing the Casbin.js authorizer, and set the subject when the frontend user identity changes. Casbin.js will automatically fetch the permission from the endpoint. (A pre-configurated casbin service API is required at the backend.) ```javascript const casbinjs = require('casbin.js'); diff --git a/src/Authorizer.ts b/src/Authorizer.ts index 85e5556..882d54b 100644 --- a/src/Authorizer.ts +++ b/src/Authorizer.ts @@ -76,11 +76,28 @@ export class Authorizer { } } - public setPermission(permission : Record | string) : void{ - if (this.permission === undefined) { - this.permission = new Permission(); + public async setPermission(permission : Record | string) : Promise{ + // Parse the permission if it's a string + let permObj: Record; + if (typeof permission === 'string') { + permObj = JSON.parse(permission); + } else { + permObj = permission; + } + + // Check if this is enforcer format (contains 'm' and/or 'p' keys) + // This format comes from Go backend's CasbinJsGetPermissionForUser + if ('m' in permObj || 'p' in permObj) { + // Use enforcer format - initialize the enforcer + const permStr = typeof permission === 'string' ? permission : JSON.stringify(permission); + await this.initEnforcer(permStr); + } else { + // Use simple permission format + if (this.permission === undefined) { + this.permission = new Permission(); + } + this.permission.load(permission); } - this.permission.load(permission); } public async initEnforcer(s: string): Promise { @@ -122,8 +139,9 @@ export class Authorizer { * @param user The current user */ public async setUser(user : string) : Promise { - if (this.mode == 'auto' && user !== this.user) { - this.user = user; + const oldUser = this.user; + this.user = user; + if (this.mode == 'auto' && user !== oldUser) { let config = Cache.loadFromLocalStorage(user); if (config === null) { config = await this.getEnforcerDataFromSvr(); @@ -135,6 +153,15 @@ export class Authorizer { public async can(action: string, object: string, domain?: string): Promise { if (this.mode == "manual") { + // Check if enforcer is available (set via enforcer format in setPermission) + if (this.enforcer !== undefined) { + if (domain == undefined) { + return await this.enforcer.enforce(this.user, object, action); + } else { + return await this.enforcer.enforce(this.user, domain, object, action); + } + } + // Fall back to simple permission check return this.permission !== undefined && this.permission.check(action, object); } else if (this.mode == "auto") { if (this.enforcer === undefined) { diff --git a/src/__test__/index.test.ts b/src/__test__/index.test.ts index 1a73dba..c7d568d 100644 --- a/src/__test__/index.test.ts +++ b/src/__test__/index.test.ts @@ -59,10 +59,34 @@ const permissionObj = { // check(authorizer); // }) -test('Manual mode', () => { +test('Manual mode', async () => { const authorizer = new Authorizer('manual'); - authorizer.setPermission(permissionObj); - check(authorizer); + await authorizer.setPermission(permissionObj); + await check(authorizer); +}) + +test('Manual mode with enforcer format (from Go backend)', async () => { + // This simulates the format returned by Go's CasbinJsGetPermissionForUser + const enforcerFormat = { + m: basicModelStr, + p: basicPolicies, + }; + const authorizer = new Authorizer('manual'); + await authorizer.setPermission(enforcerFormat); + await authorizer.setUser('alice'); + await check(authorizer); +}) + +test('Manual mode with enforcer format as JSON string', async () => { + // This simulates the format returned by Go's CasbinJsGetPermissionForUser as a string + const enforcerFormat = JSON.stringify({ + m: basicModelStr, + p: basicPolicies, + }); + const authorizer = new Authorizer('manual'); + await authorizer.setPermission(enforcerFormat); + await authorizer.setUser('alice'); + await check(authorizer); })