@holoyan/adonisjs-permissions 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +661 -0
- package/build/configure.d.ts +2 -0
- package/build/configure.js +33 -0
- package/build/index.d.ts +8 -0
- package/build/index.js +17 -0
- package/build/providers/role_permission_provider.d.ts +12 -0
- package/build/providers/role_permission_provider.js +12 -0
- package/build/src/acl.d.ts +11 -0
- package/build/src/acl.js +29 -0
- package/build/src/decorators.d.ts +4 -0
- package/build/src/decorators.js +18 -0
- package/build/src/mixins/has_permissions.d.ts +133 -0
- package/build/src/mixins/has_permissions.js +19 -0
- package/build/src/mixins/has_role_permissions.d.ts +128 -0
- package/build/src/mixins/has_role_permissions.js +10 -0
- package/build/src/mixins/has_roles.d.ts +1 -0
- package/build/src/mixins/has_roles.js +47 -0
- package/build/src/models/model_permission.d.ts +12 -0
- package/build/src/models/model_permission.js +35 -0
- package/build/src/models/model_role.d.ts +11 -0
- package/build/src/models/model_role.js +31 -0
- package/build/src/models/permission.d.ts +16 -0
- package/build/src/models/permission.js +48 -0
- package/build/src/models/role.d.ts +16 -0
- package/build/src/models/role.js +48 -0
- package/build/src/morph_map.d.ts +8 -0
- package/build/src/morph_map.js +33 -0
- package/build/src/services/base_service.d.ts +14 -0
- package/build/src/services/base_service.js +12 -0
- package/build/src/services/helper.d.ts +21 -0
- package/build/src/services/helper.js +69 -0
- package/build/src/services/model_has_role_permissions.d.ts +48 -0
- package/build/src/services/model_has_role_permissions.js +172 -0
- package/build/src/services/model_service.d.ts +8 -0
- package/build/src/services/model_service.js +31 -0
- package/build/src/services/permissions/permission_has_model_roles.d.ts +20 -0
- package/build/src/services/permissions/permission_has_model_roles.js +67 -0
- package/build/src/services/permissions/permissions_service.d.ts +92 -0
- package/build/src/services/permissions/permissions_service.js +438 -0
- package/build/src/services/roles/role_has_model_permissions.d.ts +66 -0
- package/build/src/services/roles/role_has_model_permissions.js +152 -0
- package/build/src/services/roles/roles_service.d.ts +16 -0
- package/build/src/services/roles/roles_service.js +89 -0
- package/build/src/types.d.ts +21 -0
- package/build/src/types.js +1 -0
- package/build/stubs/configs/permissions.stub +20 -0
- package/build/stubs/main.d.ts +5 -0
- package/build/stubs/main.js +7 -0
- package/build/stubs/migrations/create_db.stub +97 -0
- package/package.json +95 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,661 @@
|
|
|
1
|
+
# Role permissions system for AdonisJS V6+
|
|
2
|
+
|
|
3
|
+
## Under development!
|
|
4
|
+
|
|
5
|
+
[](https://github.com/holoyan/adonisjs-permissions/actions/workflows/test.yml)
|
|
6
|
+
[](https://github.com/holoyan/adonisjs-permissions/blob/master/LICENSE.md)
|
|
7
|
+
|
|
8
|
+
## Table of Contents
|
|
9
|
+
|
|
10
|
+
<details><summary>Click to expand</summary><p>
|
|
11
|
+
|
|
12
|
+
- [Introduction](#introduction)
|
|
13
|
+
- [Installation](#installation)
|
|
14
|
+
- [Configuration](#configuration)
|
|
15
|
+
- [Basic Usage](#basic-usage)
|
|
16
|
+
- [Creating roles and permissions](#creating-roles-and-permissions)
|
|
17
|
+
- [Assigning permissions to the roles (Globally)](#assigning-permissions-to-the-roles-globally)
|
|
18
|
+
- [Assigning permissions and roles to the users (models)](#assigning-permissions-and-roles-to-the-users-models)
|
|
19
|
+
- [Multi-model support](#multi-model-support)
|
|
20
|
+
- [Getting all roles for a user](#getting-all-roles-for-a-user)
|
|
21
|
+
- [Getting all permissions for a role](#getting-all-permissions-for-a-role)
|
|
22
|
+
- [Getting all permissions for a user (model)](#getting-all-permissions-for-a-user-model)
|
|
23
|
+
- [Getting users (models) for a permission](#getting-users-models-for-a-permission)
|
|
24
|
+
- [Getting models for a role](#getting-models-for-a-role)
|
|
25
|
+
- [Checking for a permission](#checking-for-a-permission)
|
|
26
|
+
- [Removing (revoking) roles and permissions from the model](#removing-revoking-roles-and-permissions-from-the-model)
|
|
27
|
+
- [Digging deeper](#digging-deeper)
|
|
28
|
+
- [Restricting a permission to a model (On resource)](#restricting-a-permission-to-a-model-on-resource)
|
|
29
|
+
- [Forbidding permissions](#forbidding-permissions)
|
|
30
|
+
- [Forbidding permissions on a resource](#forbidding-permissions-on-a-resource)
|
|
31
|
+
- [Checking for forbidden permissions](#checking-for-forbidden-permissions)
|
|
32
|
+
- [Unforbidding the permissions](#unforbidding-the-permissions)
|
|
33
|
+
- [Global v resource permissions (Important!)](#global-v-resource-permissions-important)
|
|
34
|
+
- [containsPermission v hasPermission](#containspermission-v-haspermission)
|
|
35
|
+
- [License](#license)
|
|
36
|
+
</p></details>
|
|
37
|
+
|
|
38
|
+
## Introduction
|
|
39
|
+
|
|
40
|
+
AdonisJs acl is an elegant and powerful package to managing roles and permissions for any AdonisJs app. With an expressive and fluent syntax, it stays out of your way as much as possible: use it when you want, ignore it when you don't.
|
|
41
|
+
|
|
42
|
+
For a quick, glanceable list of acl's features, check out [the cheat sheet](#cheat-sheet).
|
|
43
|
+
|
|
44
|
+
Once installed, you can simply tell the Acl what you want to allow:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import {Acl} from '@holoyan/adonisjs-permissions'
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
// Give a user the permission to edit
|
|
51
|
+
await Acl.model(user).allow('edit');
|
|
52
|
+
|
|
53
|
+
// Alternatively, do it through a permission
|
|
54
|
+
await Acl.permission('edit').attachToModel(user);
|
|
55
|
+
|
|
56
|
+
// You can also grant a permission only to a specific model
|
|
57
|
+
const post = await Post.first()
|
|
58
|
+
await Acl.model(user).allow('delete', post);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
To be able to use full power of Acl you should have clear understanding how it is structured and works, that's why documentation will be divided into two parts - [Basic usage](#basic-usage) and [Advanced usage](#advanced-usage) .
|
|
62
|
+
For most of the applications [Basic usage](#basic-usage) will be enough
|
|
63
|
+
|
|
64
|
+
## Installation
|
|
65
|
+
npm install ...
|
|
66
|
+
|
|
67
|
+
## Configuration
|
|
68
|
+
|
|
69
|
+
## Basic Usage
|
|
70
|
+
|
|
71
|
+
On this section we will explore basic role permission methods
|
|
72
|
+
|
|
73
|
+
### Creating roles and permissions
|
|
74
|
+
|
|
75
|
+
Let's create `create,update,read,delete` permissions and `admin,manager` roles
|
|
76
|
+
|
|
77
|
+
```typescript
|
|
78
|
+
|
|
79
|
+
// create permissions
|
|
80
|
+
const create = await Acl.permission().create({
|
|
81
|
+
slug:'create',
|
|
82
|
+
title:'Create some resource',
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
const update = await Acl.permission().create({
|
|
86
|
+
slug:'update',
|
|
87
|
+
title:'update some resource',
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
const read = await Acl.permission().create({
|
|
91
|
+
slug:'read',
|
|
92
|
+
title:'read some resource',
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
const delete = await Acl.permission().create({
|
|
96
|
+
slug:'delete',
|
|
97
|
+
title:'delete some resource',
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
// create roles
|
|
101
|
+
const admin = await Acl.role().create({
|
|
102
|
+
slug:'admin',
|
|
103
|
+
title:'Cool title for Admin',
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
const manager = await Acl.role().create({
|
|
107
|
+
slug:'manager',
|
|
108
|
+
title:'Cool title for Manager',
|
|
109
|
+
})
|
|
110
|
+
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
next step is to [assign permissions to the roles](#assigning-permissions-to-the-roles-globally)
|
|
114
|
+
|
|
115
|
+
### Assigning permissions to the roles (Globally)
|
|
116
|
+
|
|
117
|
+
Now once we've created roles and permissions let's assign them
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
await Acl.role(admin).assign('create')
|
|
121
|
+
// or you can use give() method, they are identical
|
|
122
|
+
await Acl.role(admin).give('update')
|
|
123
|
+
// or you use giveAll(), assigneAll() for bulk assign
|
|
124
|
+
await Acl.role(admin).giveAll(['read', 'delete'])
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
### Assigning permissions and roles to the users (models)
|
|
128
|
+
|
|
129
|
+
Let's see in examples how to assign [roles and permissions](#creating-roles-and-permissions) to the users
|
|
130
|
+
|
|
131
|
+
```typescript
|
|
132
|
+
import {Acl} from "@holoyan/adonisjs-permissions";
|
|
133
|
+
import User from "#models/user";
|
|
134
|
+
|
|
135
|
+
const user1 = await User.query().where(condition1).first()
|
|
136
|
+
// give manager role to the user1
|
|
137
|
+
await Acl.model(user1).assignRole(manager)
|
|
138
|
+
|
|
139
|
+
const user2 = await User.query().where(condition2).first()
|
|
140
|
+
await Acl.model(user2).assignRole(admin)
|
|
141
|
+
|
|
142
|
+
```
|
|
143
|
+
Or we can give permissions directly to users without having any role
|
|
144
|
+
|
|
145
|
+
```typescript
|
|
146
|
+
|
|
147
|
+
import {Acl} from "@holoyan/adonisjs-permissions";
|
|
148
|
+
|
|
149
|
+
// create new permission
|
|
150
|
+
const uploadFile = await Acl.permission().create({
|
|
151
|
+
slug: 'upload-file-slug',
|
|
152
|
+
title: 'permisison to upload files',
|
|
153
|
+
})
|
|
154
|
+
|
|
155
|
+
Acl.model(user1).assignDirectPermission('upload-file-slug')
|
|
156
|
+
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Multi-model support
|
|
160
|
+
|
|
161
|
+
We are not limiting to use only User model, if you have multi auth system like User and Admin you are free to use both of them with Acl.
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
```typescript
|
|
165
|
+
await Acl.model(user).assignRole(manager)
|
|
166
|
+
|
|
167
|
+
await Acl.model(admin).assignRole(admin)
|
|
168
|
+
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
## Getting roles and permissions
|
|
172
|
+
|
|
173
|
+
In this section we will see how to get roles and permissions for a model and vice versa
|
|
174
|
+
|
|
175
|
+
### Getting all roles for a user
|
|
176
|
+
|
|
177
|
+
```typescript
|
|
178
|
+
|
|
179
|
+
const roles = await Acl.model(user).roles()
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
### Getting all permissions for a role
|
|
183
|
+
|
|
184
|
+
```typescript
|
|
185
|
+
|
|
186
|
+
const roles = await Acl.role(role).permissions()
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Getting all permissions for a user (model)
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
|
|
193
|
+
const roles = await Acl.model(user).permissions()
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Getting users (models) for a permission
|
|
197
|
+
|
|
198
|
+
```typescript
|
|
199
|
+
|
|
200
|
+
const models = await Acl.permission(permission).models()
|
|
201
|
+
|
|
202
|
+
```
|
|
203
|
+
this will return array of `ModelPermission` which will contain `modelType,modelId` attributes, where `modelType` is *alias* which you had specified in [morphMap decorator](#morph-map-decorator), `modelId` is the value of column, you've specified in [getModelId]() method.
|
|
204
|
+
|
|
205
|
+
Most of the cases you will have only one model (User), it's better to use `modelsFor()` to get concrete models
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
|
|
209
|
+
const models = await Acl.permission(permission).modelsFor(User)
|
|
210
|
+
|
|
211
|
+
```
|
|
212
|
+
this will return [array of User models](https://lucid.adonisjs.com/docs/crud-operations#using-the-query-builder)
|
|
213
|
+
|
|
214
|
+
### Getting models for a role
|
|
215
|
+
|
|
216
|
+
```typescript
|
|
217
|
+
|
|
218
|
+
const models = await Acl.role(permission).models()
|
|
219
|
+
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Or if you want to get for a specific model
|
|
223
|
+
|
|
224
|
+
```typescript
|
|
225
|
+
|
|
226
|
+
const models = await Acl.role(permission).modelsFor(Admin)
|
|
227
|
+
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### Checking for a role
|
|
231
|
+
|
|
232
|
+
To check if user has role
|
|
233
|
+
|
|
234
|
+
```typescript
|
|
235
|
+
|
|
236
|
+
await Acl.model(user).hasRole('admin') // :boolean
|
|
237
|
+
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
you can pass array of roles
|
|
241
|
+
|
|
242
|
+
```typescript
|
|
243
|
+
|
|
244
|
+
// returns true only if user has all roles
|
|
245
|
+
await Acl.model(user).hasAllRoles(['admin', 'manager'])
|
|
246
|
+
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
to check if user has any of roles, will return true if user has at least one role
|
|
250
|
+
|
|
251
|
+
```typescript
|
|
252
|
+
|
|
253
|
+
await Acl.model(user).hasAnyRole(['admin', 'manager'])
|
|
254
|
+
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
### Checking for a permission
|
|
258
|
+
|
|
259
|
+
Check if user has permission
|
|
260
|
+
|
|
261
|
+
```typescript
|
|
262
|
+
|
|
263
|
+
await Acl.model(user).hasPermission('update')
|
|
264
|
+
// or
|
|
265
|
+
await Acl.model(user).can('update') // alias for hasPermission() method
|
|
266
|
+
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
To check array of permissions
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
|
|
273
|
+
// returns true only if user has all permissions
|
|
274
|
+
await Acl.model(user).hasAllPermissions(['update', 'delete'])
|
|
275
|
+
// or
|
|
276
|
+
await Acl.model(user).canAll(['update', 'delete']) // alias for hasAllPermissions() method
|
|
277
|
+
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
to check if user has any of permission, will return true if user has at least one permission
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
|
|
284
|
+
// returns true only if user has all permissions
|
|
285
|
+
await Acl.model(user).hasAnyPermission(['update', 'delete'])
|
|
286
|
+
// or
|
|
287
|
+
await Acl.model(user).canAny(['update', 'delete']) // alias for hasAnyPermission() method
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
Same applies for role
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
|
|
295
|
+
await Acl.role(role).hasPermission('update')
|
|
296
|
+
await Acl.role(role).hasAllPermissions(['update', 'read'])
|
|
297
|
+
await Acl.role(role).hasAnyPermission(['update', 'read'])
|
|
298
|
+
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
### Removing (revoking) roles and permissions from the model
|
|
302
|
+
|
|
303
|
+
To remove role from the user we can use `revoke` method
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
|
|
307
|
+
await Acl.model(user).revokeRole('admin')
|
|
308
|
+
await Acl.model(user).revokeAllRoles(['admin', 'manager'])
|
|
309
|
+
|
|
310
|
+
// will remove all assigned roles
|
|
311
|
+
await Acl.model(user).flushRoles()
|
|
312
|
+
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
Removing permissions from the user
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
await Acl.model(user).revokePermission('update')
|
|
319
|
+
// await Acl.model(user).hasPermission('update') will return false
|
|
320
|
+
|
|
321
|
+
await Acl.model(user).revokeAllPermissions(['update', 'delete'])
|
|
322
|
+
|
|
323
|
+
// will remove all assigned permissions
|
|
324
|
+
await Acl.model(user).flushPermissions()
|
|
325
|
+
|
|
326
|
+
// revokes all roles and permissions for a user
|
|
327
|
+
await Acl.model(user).flush()
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
|
|
331
|
+
Removing permissions from the role
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
await Acl.role(role).revokePermission('update')
|
|
335
|
+
// or
|
|
336
|
+
await Acl.role(role).revoke('update') // alias for revokePermission - WORKS ONLY on roles
|
|
337
|
+
|
|
338
|
+
await Acl.role(role).revokeAllPermissions(['update', 'delete'])
|
|
339
|
+
// alias revokeAll(['update', 'delete']) method availalbe ONLY on roles
|
|
340
|
+
|
|
341
|
+
// remove all assigned permissions
|
|
342
|
+
await Acl.role(role).flushPermissions()
|
|
343
|
+
// alias flush() method availalbe ONLY on roles
|
|
344
|
+
|
|
345
|
+
```
|
|
346
|
+
|
|
347
|
+
|
|
348
|
+
### Deleting roles and permissions (Important!)
|
|
349
|
+
|
|
350
|
+
> Important! use Acl to delete roles and permissions, under the hood Acl does some checking
|
|
351
|
+
|
|
352
|
+
```typescript
|
|
353
|
+
|
|
354
|
+
await Acl.role().delete('admin')
|
|
355
|
+
|
|
356
|
+
await Acl.permission().delete('edit')
|
|
357
|
+
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
To see in dept usage of this methods check [next section](#digging-deeper)
|
|
361
|
+
|
|
362
|
+
## Digging deeper
|
|
363
|
+
|
|
364
|
+
In [previous](#basic-usage) section we looked basic examples and usage, most of the time basic usage probably will be enough for your project but there are much more we can do with `Acl`
|
|
365
|
+
|
|
366
|
+
### Restricting a permission to a model (On resource)
|
|
367
|
+
|
|
368
|
+
Sometimes you might want to restrict a permission to a specific model type. Simply pass the model name as a second argument:
|
|
369
|
+
|
|
370
|
+
```typescript
|
|
371
|
+
import Product from "#models/product";
|
|
372
|
+
|
|
373
|
+
await Acl.model(user).assignDirectPermission('edit', Product)
|
|
374
|
+
|
|
375
|
+
```
|
|
376
|
+
>Just don't forget to add model `MorphMap` decorator on Product class
|
|
377
|
+
|
|
378
|
+
```typescript
|
|
379
|
+
|
|
380
|
+
@MorphMap('products')
|
|
381
|
+
export default class Product extends BaseModel {
|
|
382
|
+
// other code
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
```
|
|
386
|
+
|
|
387
|
+
>Warning: All models which interact with Acl **MUST** use [MorphMap]() decorator
|
|
388
|
+
|
|
389
|
+
In this case we check permission again
|
|
390
|
+
|
|
391
|
+
```typescript
|
|
392
|
+
import Product from "#models/product";
|
|
393
|
+
import Post from "#models/post";
|
|
394
|
+
|
|
395
|
+
const productModel1 = Product.first()
|
|
396
|
+
const productModel50 = Product.first()
|
|
397
|
+
const postModel = Post.first()
|
|
398
|
+
|
|
399
|
+
await Acl.model(user).hasPermission('edit', productModel1) // true
|
|
400
|
+
await Acl.model(user).hasPermission('edit', productModel50) // true
|
|
401
|
+
// ... for all Product model instances it will return true
|
|
402
|
+
await Acl.model(user).hasPermission('edit', Product) // true
|
|
403
|
+
|
|
404
|
+
await Acl.model(user).hasPermission('edit', postModel) // false
|
|
405
|
+
await Acl.model(user).hasPermission('edit', Post) // false
|
|
406
|
+
|
|
407
|
+
await Acl.model(user).hasPermission('edit') // false
|
|
408
|
+
|
|
409
|
+
// containsPermission() method will tell if user has 'edit' permission attached at all
|
|
410
|
+
await Acl.model(user).containsPermission('edit') // true
|
|
411
|
+
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
Check [ContainsPermission vs hasPermission](#containspermission-v-haspermission) section for more details
|
|
415
|
+
|
|
416
|
+
We can restrict even more, and give permission to the specific model
|
|
417
|
+
|
|
418
|
+
```typescript
|
|
419
|
+
|
|
420
|
+
import Product from "#models/product";
|
|
421
|
+
|
|
422
|
+
const product1 = Product.find(1)
|
|
423
|
+
|
|
424
|
+
await Acl.model(user).assignDirectPermission('edit', product1)
|
|
425
|
+
|
|
426
|
+
const product2 = Product.find(2)
|
|
427
|
+
|
|
428
|
+
await Acl.model(user).hasPermission('edit', product1) // true
|
|
429
|
+
await Acl.model(user).hasPermission('edit', product2) // false
|
|
430
|
+
|
|
431
|
+
await Acl.model(user).hasPermission('edit', Product) // false
|
|
432
|
+
|
|
433
|
+
await Acl.model(user).hasPermission('edit') // false
|
|
434
|
+
await Acl.model(user).containsPermission('edit') // true
|
|
435
|
+
|
|
436
|
+
```
|
|
437
|
+
|
|
438
|
+
This will behave same way if assign permission through the role instead of direct
|
|
439
|
+
|
|
440
|
+
```typescript
|
|
441
|
+
|
|
442
|
+
const product1 = Product.find(1)
|
|
443
|
+
|
|
444
|
+
await Acl.role(admin).assign('edit', product1)
|
|
445
|
+
|
|
446
|
+
const user = await User.first()
|
|
447
|
+
|
|
448
|
+
await Acl.model(user).assignRole(role)
|
|
449
|
+
|
|
450
|
+
// then if we start checking, result will be same
|
|
451
|
+
|
|
452
|
+
const product2 = Product.find(2)
|
|
453
|
+
|
|
454
|
+
await Acl.model(user).hasPermission('edit', product1) // true
|
|
455
|
+
await Acl.model(user).hasPermission('edit', product2) // false
|
|
456
|
+
|
|
457
|
+
await Acl.model(user).hasPermission('edit', Product) // false
|
|
458
|
+
|
|
459
|
+
await Acl.model(user).hasPermission('edit') // false
|
|
460
|
+
await Acl.model(user).containsPermission('edit') // true
|
|
461
|
+
|
|
462
|
+
```
|
|
463
|
+
|
|
464
|
+
### Forbidding permissions
|
|
465
|
+
|
|
466
|
+
Let's imagine a situation when your `manager` role has `create,update,read,delete` permissions. All your users have `manager` role but there are small amount of users you want to give `manager` role but same time do not allow `delete` action.
|
|
467
|
+
Good news!, we can do that
|
|
468
|
+
|
|
469
|
+
```typescript
|
|
470
|
+
|
|
471
|
+
await Acl.role(manager).giveAll(['create','update','read','delete'])
|
|
472
|
+
|
|
473
|
+
// assigning to the users
|
|
474
|
+
await Acl.model(user1).assignRole(manager)
|
|
475
|
+
|
|
476
|
+
await Acl.model(user3).assignRole(manager)
|
|
477
|
+
await Acl.model(user3).forbid('delete')
|
|
478
|
+
|
|
479
|
+
await Acl.model(user1).hasRole(manager) // true
|
|
480
|
+
await Acl.model(user1).hasPermission('delete') // true
|
|
481
|
+
|
|
482
|
+
await Acl.model(user3).hasRole(manager) // true
|
|
483
|
+
await Acl.model(user3).hasPermission('delete') // false
|
|
484
|
+
|
|
485
|
+
await Acl.model(user3).containsPermission('delete') // true
|
|
486
|
+
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
### Forbidding permissions on a resource
|
|
490
|
+
|
|
491
|
+
You can also forbid single action on a resource
|
|
492
|
+
|
|
493
|
+
```typescript
|
|
494
|
+
|
|
495
|
+
const post = Post.find(id1ToFind)
|
|
496
|
+
|
|
497
|
+
await Acl.model(user3).forbid('delete', post)
|
|
498
|
+
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Checking for forbidden permissions
|
|
502
|
+
|
|
503
|
+
In [previous](#forbidding-permissions) section we saw how to forbid certain permissions for the model, even if user has that permission through the role, now we will look how to check if permission is forbidden or not
|
|
504
|
+
|
|
505
|
+
```typescript
|
|
506
|
+
|
|
507
|
+
await Acl.model(user3).assignRole(manager)
|
|
508
|
+
await Acl.model(user3).forbid('delete')
|
|
509
|
+
|
|
510
|
+
await Acl.model(user3).forbidden('delete') // true
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
const post1 = Post.find(id1ToFind)
|
|
514
|
+
|
|
515
|
+
|
|
516
|
+
await Acl.model(user).allow('edit', Post) // allow for all posts
|
|
517
|
+
await Acl.model(user).forbid('edit', post1) // except post1
|
|
518
|
+
|
|
519
|
+
await Acl.model(user).forbidden('edit', post1) // true
|
|
520
|
+
|
|
521
|
+
const post7 = Post.find(id7ToFind)
|
|
522
|
+
await Acl.model(user).forbidden('edit', post7) // false becouse 'edit' action forbidden only for post1 instance
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### Unforbidding the permissions
|
|
526
|
+
|
|
527
|
+
```typescript
|
|
528
|
+
|
|
529
|
+
await Acl.model(user3).assignRole(manager)
|
|
530
|
+
await Acl.model(user3).forbid('delete')
|
|
531
|
+
|
|
532
|
+
await Acl.model(user3).forbidden('delete') // true
|
|
533
|
+
await Acl.model(user3).hasPermission('delete') // false
|
|
534
|
+
await Acl.model(user3).containsPermission('delete') // true
|
|
535
|
+
|
|
536
|
+
await Acl.model(user3).unforbid('delete')
|
|
537
|
+
await Acl.model(user3).forbidden('delete') // false
|
|
538
|
+
await Acl.model(user3).hasPermission('delete') // true
|
|
539
|
+
|
|
540
|
+
```
|
|
541
|
+
Same behaviour applies with roles
|
|
542
|
+
|
|
543
|
+
```typescript
|
|
544
|
+
await Acl.role(role).assignRole(manager)
|
|
545
|
+
await Acl.role(role).forbid('delete')
|
|
546
|
+
|
|
547
|
+
await Acl.role(role).forbidden('delete') // true
|
|
548
|
+
await Acl.role(role).hasPermission('delete') // false
|
|
549
|
+
await Acl.role(role).containsPermission('delete') // true
|
|
550
|
+
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### Global v resource permissions (Important!)
|
|
554
|
+
|
|
555
|
+
> Important! Action performed globally will affect on resource models
|
|
556
|
+
|
|
557
|
+
It is very important to understood difference between global and resource permissions and their scope.
|
|
558
|
+
Look at this way, if there is no `entity` model then action will be performed **globally**, otherwise **on resource**
|
|
559
|
+
|
|
560
|
+
```typescript
|
|
561
|
+
// global actions
|
|
562
|
+
import {Acl} from "@holoyan/adonisjs-permissions";
|
|
563
|
+
|
|
564
|
+
// Give a user the permission to edit
|
|
565
|
+
await Acl.model(user).allow('edit');
|
|
566
|
+
|
|
567
|
+
Acl.model(user).assignDirectPermission('uploadFile')
|
|
568
|
+
|
|
569
|
+
await Acl.model(user).forbid('delete')
|
|
570
|
+
|
|
571
|
+
await Acl.model(user).hasPermission('create')
|
|
572
|
+
await Acl.model(user).unforbid('delete')
|
|
573
|
+
// ... and so on
|
|
574
|
+
|
|
575
|
+
```
|
|
576
|
+
|
|
577
|
+
```typescript
|
|
578
|
+
// On resource actions
|
|
579
|
+
|
|
580
|
+
await Acl.role(admin).assign('edit', product1)
|
|
581
|
+
await Acl.model(user).hasPermission('edit', product1)
|
|
582
|
+
await Acl.model(user).assignDirectPermission('edit', Post)
|
|
583
|
+
|
|
584
|
+
```
|
|
585
|
+
|
|
586
|
+
As you can see if `entity` (product1, Post and so on) is specified then it's a *on resource* action
|
|
587
|
+
|
|
588
|
+
Now let's see few examples
|
|
589
|
+
|
|
590
|
+
```typescript
|
|
591
|
+
import {Acl} from "@holoyan/adonisjs-permissions";
|
|
592
|
+
|
|
593
|
+
// Global action
|
|
594
|
+
await Acl.model(user).allow('edit');
|
|
595
|
+
|
|
596
|
+
const product1 = Product.first();
|
|
597
|
+
|
|
598
|
+
await Acl.model(user).hasPermission('edit') // true
|
|
599
|
+
await Acl.model(user).hasPermission('edit', product1) // true becouse 'edit' permission assigned globaly
|
|
600
|
+
await Acl.model(user).hasPermission('edit', ImageModel) // true becouse 'edit' permission assigned globaly
|
|
601
|
+
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
Now if do same but assign on Resource, result will be different
|
|
605
|
+
|
|
606
|
+
```typescript
|
|
607
|
+
|
|
608
|
+
const product1 = Product.first();
|
|
609
|
+
|
|
610
|
+
await Acl.model(user).allow('edit', product1);
|
|
611
|
+
|
|
612
|
+
await Acl.model(user).hasPermission('edit', product1) // true becouse 'edit' permission assigned to this specific model instance
|
|
613
|
+
|
|
614
|
+
await Acl.model(user).hasPermission('edit') // false
|
|
615
|
+
await Acl.model(user).hasPermission('edit', Product) // false becouse 'edit' permission assigned to the specific model instance
|
|
616
|
+
|
|
617
|
+
```
|
|
618
|
+
|
|
619
|
+
let's see one more example
|
|
620
|
+
|
|
621
|
+
```typescript
|
|
622
|
+
|
|
623
|
+
await Acl.model(user).allow('edit', Product); // assing to Product model, for all Product instances it will be true
|
|
624
|
+
|
|
625
|
+
const product1 = Product.first();
|
|
626
|
+
await Acl.model(user).hasPermission('edit', product1) // true
|
|
627
|
+
const product2 = Product.find(someId);
|
|
628
|
+
await Acl.model(user).hasPermission('edit', product2) // true
|
|
629
|
+
await Acl.model(user).hasPermission('edit', Product) // true
|
|
630
|
+
|
|
631
|
+
await Acl.model(user).hasPermission('edit') // false , becouse it's not global, it's only on Product resrouce
|
|
632
|
+
|
|
633
|
+
```
|
|
634
|
+
|
|
635
|
+
Anytime you can use `containsPermission()` method to check if user has it
|
|
636
|
+
|
|
637
|
+
### containsPermission v hasPermission
|
|
638
|
+
|
|
639
|
+
As you've already seen there are difference between `containsPermission` and `hasPermission`. `containsPermission()` method will return `true` if user has that permission, it doesn't matter if it's *global*, *on resource* or *forbidden*
|
|
640
|
+
|
|
641
|
+
Lets in example see this difference
|
|
642
|
+
|
|
643
|
+
```typescript
|
|
644
|
+
|
|
645
|
+
|
|
646
|
+
await Acl.model(user).allow('edit'); // assing globally
|
|
647
|
+
await Acl.model(user).containsPermission('edit') // true
|
|
648
|
+
|
|
649
|
+
|
|
650
|
+
await Acl.model(user).allow('delete', Post); // assing on resource
|
|
651
|
+
await Acl.model(user).containsPermission('delete') // true
|
|
652
|
+
|
|
653
|
+
|
|
654
|
+
await Acl.model(user).forbid('read'); // forbid read action
|
|
655
|
+
await Acl.model(user).containsPermission('read') // true
|
|
656
|
+
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
## License
|
|
660
|
+
|
|
661
|
+
MIT
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
|--------------------------------------------------------------------------
|
|
3
|
+
| Configure hook
|
|
4
|
+
|--------------------------------------------------------------------------
|
|
5
|
+
|
|
|
6
|
+
| The configure hook is called when someone runs "node ace configure <package>"
|
|
7
|
+
| command. You are free to perform any operations inside this function to
|
|
8
|
+
| configure the package.
|
|
9
|
+
|
|
|
10
|
+
| To make things easier, you have access to the underlying "ConfigureCommand"
|
|
11
|
+
| instance and you can use codemods to modify the source files.
|
|
12
|
+
|
|
|
13
|
+
*/
|
|
14
|
+
import { stubsRoot } from './stubs/main.js';
|
|
15
|
+
export async function configure(_command) {
|
|
16
|
+
const codemods = await _command.createCodemods();
|
|
17
|
+
/**
|
|
18
|
+
* Publish config file
|
|
19
|
+
*/
|
|
20
|
+
await codemods.makeUsingStub(stubsRoot, 'configs/permissions.stub', {});
|
|
21
|
+
/**
|
|
22
|
+
* Publish migration file
|
|
23
|
+
*/
|
|
24
|
+
await codemods.makeUsingStub(stubsRoot, 'migrations/create_db.stub', {
|
|
25
|
+
prefix: new Date().getTime(),
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Register provider
|
|
29
|
+
*/
|
|
30
|
+
await codemods.updateRcFile((rcFile) => {
|
|
31
|
+
rcFile.addProvider('@holoyan/adonisjs-permissions/role_permission_provider');
|
|
32
|
+
});
|
|
33
|
+
}
|