Skip to content

Commit d48c298

Browse files
Copilothsluoyz
andcommitted
Fix setPermission to support enforcer format from Go backend
- Made setPermission() async to support both simple and enforcer formats - Auto-detect enforcer format (with 'm' and 'p' keys) and use initEnforcer() - Update can() to check for enforcer in manual mode - Update setUser() to set user in all modes (needed for enforcer in manual mode) - Add comprehensive tests for new functionality - Update README with examples of both formats Co-authored-by: hsluoyz <3787410+hsluoyz@users.noreply.github.com>
1 parent 7c277e9 commit d48c298

File tree

3 files changed

+86
-10
lines changed

3 files changed

+86
-10
lines changed

README.md

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,8 @@ We demonstrate the usage of Casbin.js with [a React app](https://github.com/casb
1313

1414

1515
You can use `manual` mode in Casbin.js, and set the permission whenever you wish.
16+
17+
### Simple Permission Format
1618
```javascript
1719
const casbinjs = require('casbin.js');
1820

@@ -27,7 +29,7 @@ const permission = {
2729
// Run casbin.js in manual mode, which requires you to set the permission manually.
2830
const authorizer = new casbinjs.Authorizer("manual");
2931

30-
authorizer.setPermission(permission);
32+
await authorizer.setPermission(permission);
3133

3234
authorizer.can("read", "data1").then(result => {
3335
console.log(result)
@@ -37,6 +39,29 @@ authorizer.cannot("write", "data2").then(result => {
3739
});
3840
```
3941

42+
### Using Enforcer Format from Go Backend
43+
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.
44+
45+
```javascript
46+
const casbinjs = require('casbin.js');
47+
48+
// Get permission from your Go backend API
49+
const responseFromApi = await fetch('http://your-api/casbin-permission').then(r => r.json());
50+
51+
const authorizer = new casbinjs.Authorizer("manual");
52+
53+
// Set permission with enforcer format (contains 'm' and 'p' keys)
54+
await authorizer.setPermission(responseFromApi);
55+
56+
// Set the current user
57+
await authorizer.setUser("alice");
58+
59+
// Evaluate permissions
60+
authorizer.can("read", "data1").then(result => {
61+
console.log(result)
62+
});
63+
```
64+
4065
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.)
4166
```javascript
4267
const casbinjs = require('casbin.js');

src/Authorizer.ts

Lines changed: 33 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,11 +76,28 @@ export class Authorizer {
7676
}
7777
}
7878

79-
public setPermission(permission : Record<string, unknown> | string) : void{
80-
if (this.permission === undefined) {
81-
this.permission = new Permission();
79+
public async setPermission(permission : Record<string, unknown> | string) : Promise<void>{
80+
// Parse the permission if it's a string
81+
let permObj: Record<string, unknown>;
82+
if (typeof permission === 'string') {
83+
permObj = JSON.parse(permission);
84+
} else {
85+
permObj = permission;
86+
}
87+
88+
// Check if this is enforcer format (contains 'm' and/or 'p' keys)
89+
// This format comes from Go backend's CasbinJsGetPermissionForUser
90+
if ('m' in permObj || 'p' in permObj) {
91+
// Use enforcer format - initialize the enforcer
92+
const permStr = typeof permission === 'string' ? permission : JSON.stringify(permission);
93+
await this.initEnforcer(permStr);
94+
} else {
95+
// Use simple permission format
96+
if (this.permission === undefined) {
97+
this.permission = new Permission();
98+
}
99+
this.permission.load(permission);
82100
}
83-
this.permission.load(permission);
84101
}
85102

86103
public async initEnforcer(s: string): Promise<void> {
@@ -122,8 +139,9 @@ export class Authorizer {
122139
* @param user The current user
123140
*/
124141
public async setUser(user : string) : Promise<void> {
125-
if (this.mode == 'auto' && user !== this.user) {
126-
this.user = user;
142+
const oldUser = this.user;
143+
this.user = user;
144+
if (this.mode == 'auto' && user !== oldUser) {
127145
let config = Cache.loadFromLocalStorage(user);
128146
if (config === null) {
129147
config = await this.getEnforcerDataFromSvr();
@@ -135,6 +153,15 @@ export class Authorizer {
135153

136154
public async can(action: string, object: string, domain?: string): Promise<boolean> {
137155
if (this.mode == "manual") {
156+
// Check if enforcer is available (set via enforcer format in setPermission)
157+
if (this.enforcer !== undefined) {
158+
if (domain == undefined) {
159+
return await this.enforcer.enforce(this.user, object, action);
160+
} else {
161+
return await this.enforcer.enforce(this.user, domain, object, action);
162+
}
163+
}
164+
// Fall back to simple permission check
138165
return this.permission !== undefined && this.permission.check(action, object);
139166
} else if (this.mode == "auto") {
140167
if (this.enforcer === undefined) {

src/__test__/index.test.ts

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,34 @@ const permissionObj = {
5959
// check(authorizer);
6060
// })
6161

62-
test('Manual mode', () => {
62+
test('Manual mode', async () => {
6363
const authorizer = new Authorizer('manual');
64-
authorizer.setPermission(permissionObj);
65-
check(authorizer);
64+
await authorizer.setPermission(permissionObj);
65+
await check(authorizer);
66+
})
67+
68+
test('Manual mode with enforcer format (from Go backend)', async () => {
69+
// This simulates the format returned by Go's CasbinJsGetPermissionForUser
70+
const enforcerFormat = {
71+
m: basicModelStr,
72+
p: basicPolicies,
73+
};
74+
const authorizer = new Authorizer('manual');
75+
await authorizer.setPermission(enforcerFormat);
76+
await authorizer.setUser('alice');
77+
await check(authorizer);
78+
})
79+
80+
test('Manual mode with enforcer format as JSON string', async () => {
81+
// This simulates the format returned by Go's CasbinJsGetPermissionForUser as a string
82+
const enforcerFormat = JSON.stringify({
83+
m: basicModelStr,
84+
p: basicPolicies,
85+
});
86+
const authorizer = new Authorizer('manual');
87+
await authorizer.setPermission(enforcerFormat);
88+
await authorizer.setUser('alice');
89+
await check(authorizer);
6690
})
6791

6892

0 commit comments

Comments
 (0)