Skip to content

Commit 4502a0b

Browse files
authored
docs(chore): refactor readme to convert bullets into headings
as it's hard to reference specific sections when bulleted vs permalink-able headings.
1 parent e4e9f64 commit 4502a0b

File tree

1 file changed

+62
-37
lines changed

1 file changed

+62
-37
lines changed

README.md

Lines changed: 62 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -22,17 +22,7 @@
2222

2323
## Overview
2424

25-
A loopback-next extension for authorization in loopback applications. Its a very simplistic yet powerful and effective implementation using simple string based permissions.
26-
27-
It provides three ways of integration
28-
29-
1. **User level permissions only** - Permissions are associated directly to user. In this case, each user entry in DB contains specific array of permission keys.
30-
2. **Role based permissions** - Permissions are associated to roles and users have a specific role attached. This actually reduces redundancy in DB a lot, as most of the time, users will have many common permissions. If that is not the case for you, then, use method #1 above.
31-
3. **Role based permissions with user level override** - This is the most flexible architecture. In this case, method #2 is implemented as is. On top of it, we also add user-level permissions override, allow/deny permissions over role permissions. So, say there is user who can perform all admin role actions except he cannot remove users from the system. So, DeleteUser permission can be denied at user level and role can be set as Admin for the user.
32-
33-
[Extension enhancement using CASBIN authorisation](#Extension-enhancement-using-CASBIN-authorisation)
34-
35-
Refer to the usage section below for details on integration
25+
A LoopBack 4 extension for Authorization Capabilities. It's very simple to integration yet powerful and effective.
3626

3727
## Install
3828

@@ -46,9 +36,35 @@ For a quick starter guide, you can refer to our [loopback 4 starter](https://git
4636

4737
## Usage
4838

39+
### Ways of Integration:
40+
41+
On a higher level, it provides three ways of integration:
42+
43+
#### 1. User Level Permissions Only
44+
45+
Where permissions are associated directly to user. In this case, each user entry in DB contains specific array of permission keys.
46+
47+
#### 2. Role Based Permissions
48+
49+
Where permissions are associated to roles and users have a specific role attached. This actually reduces redundancy in DB a lot, as most of the time, users will have many common permissions. If that is not the case for you, then, use the first method.
50+
51+
#### 3. Role Based Permissions with User Level Flexibility
52+
53+
This is the most flexible architecture. In this case, method #2 is implemented as is.
54+
55+
On top of it, we also add user-level permissions override, allow/deny permissions over role permissions. So, say there is user who can perform all admin role actions except he cannot remove users from the system. So, DeleteUser permission can be denied at user level and role can be set as Admin for the user.
56+
57+
[Extension enhancement using CASBIN authorisation](#Extension-enhancement-using-CASBIN-authorisation)
58+
59+
Refer to the usage section below for details on integration.
60+
4961
In order to use this component into your LoopBack application, please follow below steps.
5062

51-
- Add component to application.
63+
### Steps
64+
65+
#### Bind Component
66+
67+
Add `AuthorizationComponent` to your application, Like below:
5268

5369
```ts
5470
this.bind(AuthorizationBindings.CONFIG).to({
@@ -57,7 +73,9 @@ this.bind(AuthorizationBindings.CONFIG).to({
5773
this.component(AuthorizationComponent);
5874
```
5975

60-
- If using method #1 from above, implement Permissions interface in User model and add permissions array.
76+
#### Implement Permission Interface
77+
78+
If using method #1 from above, implement Permissions interface in User model and add permissions array.
6179

6280
```ts
6381
@model({
@@ -80,7 +98,7 @@ export class User extends Entity implements Permissions<string> {
8098
}
8199
```
82100

83-
- If using method #2 or #3 from above, implement Permissions interface in Role model and add permissions array.
101+
If using method #2 or #3 from above, implement Permissions interface in Role model and add permissions array.
84102

85103
```ts
86104
@model({
@@ -103,7 +121,9 @@ export class Role extends Entity implements Permissions<string> {
103121
}
104122
```
105123

106-
- If using method #3 from above, implement UserPermissionsOverride interface in User model and add user level permissions array as below.
124+
#### Implement `UserPermissionsOverride` Interface
125+
126+
If using method #3 from above, implement UserPermissionsOverride interface in User model and add user level permissions array as below.
107127
Do this if there is a use-case of explicit allow/deny of permissions at user-level in the application.
108128
You can skip otherwise.
109129

@@ -128,7 +148,11 @@ export class User extends Entity implements UserPermissionsOverride<string> {
128148
}
129149
```
130150

131-
- For method #3, we also provide a simple provider function [_AuthorizationBindings.USER_PERMISSIONS_](<[./src/providers/user-permissions.provider.ts](https://github.com/sourcefuse/loopback4-authorization/blob/master/src/providers/user-permissions.provider.ts)>) to evaluate the user permissions based on its role permissions and user-level overrides. Just inject it
151+
#### User Permissions Provider
152+
153+
For method #3, This extension exposes a provider function [AuthorizationBindings.USER_PERMISSIONS](https://github.com/sourcefuse/loopback4-authorization/blob/master/src/providers/user-permissions.provider.ts) to evaluate the user permissions based on its role permissions and user-level overrides.
154+
155+
Just inject it like below:
132156

133157
```ts
134158
@inject(AuthorizationBindings.USER_PERMISSIONS)
@@ -141,8 +165,7 @@ and invoke it
141165
const permissions = this.getUserPermissions(user.permissions, role.permissions);
142166
```
143167

144-
- Add a step in custom sequence to check for authorization whenever any end
145-
point is hit.
168+
Add a step in custom sequence to check for authorization whenever any endpoint is hit.
146169

147170
```ts
148171
import {inject} from '@loopback/context';
@@ -223,8 +246,7 @@ export class MySequence implements SequenceHandler {
223246

224247
The above sequence also contains user authentication using [loopback4-authentication](https://github.com/sourcefuse/loopback4-authentication) package. You can refer to the documentation for the same for more details.
225248

226-
- Now we can add access permission keys to the controller methods using authorize
227-
decorator as below.
249+
Now we can add access permission keys to the controller methods using authorize decorator as below:
228250

229251
```ts
230252
@authorize(['CreateRole'])
@@ -244,7 +266,7 @@ async create(@requestBody() role: Role): Promise<Role> {
244266
```
245267

246268
This endpoint will only be accessible if logged in user has permission
247-
'CreateRole'.
269+
`CreateRole`.
248270

249271
A good practice is to keep all permission strings in a separate enum file like this.
250272

@@ -278,28 +300,31 @@ export const enum PermissionKey {
278300
}
279301
```
280302

281-
- To Override the permissions provided in enum `permissionKey` file:
303+
### Overriding Permissions
282304

283-
If the userPermission object is provided,it overrides the default permissions in the authorizationMetadata object.
305+
API endpoints provided by ARC API (aka Sourceloop) services have their permissions pre-defined in them bundled.
284306

285-
For providing a userPermission object with custom permissions for specific controller methods, you can bind the following in `application.ts` file in your application.
307+
In order to override them you can bind your custom permissions in the `AuthorizationBindings.PERMISSION` binding key.
308+
This accepts an object that should have Controller class name as the root level key and the value of which is another object of method to permissions array mapping.
286309

287-
```ts
310+
Like below:
288311

312+
```ts
289313
this.bind(AuthorizationBindings.PERMISSION).to({
290-
MessageController:{
291-
create:['CreateMessage','ViewMessage'],
292-
updateAll:['UpdateMessage','ViewMessage','ViewMessageNum]
314+
MessageController: {
315+
create: ['CreateMessage', 'ViewMessage'],
316+
updateAll: ['UpdateMessage', 'ViewMessage', 'ViewMessageNum']
293317
}
294-
AttachmentFileController:{
295-
create:['CreateAttachmentFile','ViewAttachmentFile'],
296-
updateAll:['UpdateAttachmentFile','ViewAttachmentFileNum']
318+
AttachmentFileController: {
319+
create: ['CreateAttachmentFile', 'ViewAttachmentFile'],
320+
updateAll: ['UpdateAttachmentFile', 'ViewAttachmentFileNum']
297321
}
298-
})
299-
322+
});
300323
```
301324

302-
# Serving the static files:
325+
You can easily check the name of the controller and it's method name from the source code of the services or from the Swagger UI (clicking the endpoint in swagger append the controller and method name in the URL like `LoginController.login` where `login` is the method name).
326+
327+
## Serving the static files:
303328

304329
Authorization configuration binding sets up paths that can be accessed without any authorization checks, allowing static files to be served directly from the root URL of the application.The allowAlwaysPaths property is used to define these paths for the files in public directory i.e for a test.html file in public directory ,one can provide its path as follows:
305330

@@ -316,7 +341,7 @@ this.static('/', path.join(__dirname, '../public'));
316341
317342
```
318343

319-
If ,in case the file is in some other folder then `app.static()` can be called multiple times to configure the app to serve static assets from different directories.
344+
If, in case the file is in some other folder then `app.static()` can be called multiple times to configure the app to serve static assets from different directories.
320345

321346
```
322347
this.static('/', path.join(__dirname, '../public'));
@@ -326,14 +351,14 @@ this.static('/downloads', path.join(__dirname, '../downloads'));
326351

327352
For more details,refer [here](https://loopback.io/doc/en/lb4/Serving-static-files.html#:~:text=One%20of%20the%20basic%20requirements,the%20API%20are%20explained%20below.)
328353

329-
# Extension enhancement using CASBIN authorisation
354+
## Extension enhancement using CASBIN authorisation
330355

331356
As a further enhancement to these methods, we are using [casbin library](https://casbin.org/docs/en/overview) to define permissions at level of entity or resource associated with an API call. Casbin authorisation implementation can be performed in two ways:
332357

333358
1. **Using default casbin policy document** - Define policy document in default casbin format in the app, and configure authorise decorator to use those policies.
334359
2. **Defining custom logic to form dynamic policies** - Implement dynamic permissions based on app logic in casbin-enforcer-config provider. Authorisation extension will dynamically create casbin policy using this business logic to give the authorisation decisions.
335360

336-
## Usage
361+
### Casbin Usage
337362

338363
In order to use this enhacement into your LoopBack application, please follow below steps.
339364

0 commit comments

Comments
 (0)