Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand All @@ -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)
Expand All @@ -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');
Expand Down
39 changes: 33 additions & 6 deletions src/Authorizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

interface BaseResponse {
message: string;
data: any;

Check warning on line 9 in src/Authorizer.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 9 in src/Authorizer.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 9 in src/Authorizer.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type

Check warning on line 9 in src/Authorizer.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected any. Specify a different type
}

type Mode = "auto" | "cookies" | "manual"
Expand Down Expand Up @@ -76,11 +76,28 @@
}
}

public setPermission(permission : Record<string, unknown> | string) : void{
if (this.permission === undefined) {
this.permission = new Permission();
public async setPermission(permission : Record<string, unknown> | string) : Promise<void>{
// Parse the permission if it's a string
let permObj: Record<string, unknown>;
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<void> {
Expand Down Expand Up @@ -122,8 +139,9 @@
* @param user The current user
*/
public async setUser(user : string) : Promise<void> {
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();
Expand All @@ -135,6 +153,15 @@

public async can(action: string, object: string, domain?: string): Promise<boolean> {
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) {
Expand Down
30 changes: 27 additions & 3 deletions src/__test__/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
})


Expand Down
Loading