Skip to content

Commit 5d4ce7f

Browse files
committed
docs(ability): adds details about merging permissions
Closes #43
1 parent 1cf2e63 commit 5d4ce7f

File tree

1 file changed

+38
-13
lines changed

1 file changed

+38
-13
lines changed

docs/_posts/2017-07-23-use-cases.md

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ layout: default
33
title: "Other interesting use cases"
44
date: 2017-07-23 9:40:48 +0300
55
categories: [abilities]
6-
tags: [merging abilities, feature flags, hardware capabilities]
6+
tags: [merging abilities, merge permissions, combine rules, feature flags, hardware capabilities]
77
---
88

99
The primary goal of CASL is to provide a simple way to declare user abilities in application. In the same time application may or may not have some capabilities depending on hardware, user's culture, subscription plan, etc. Lets see how these cases can be covered by CASL.
@@ -31,31 +31,56 @@ const ability = AbilityBuilder.define(can => {
3131

3232
And later in UI check the capability with help of `ability.can('read', 'wifi')`. You can mix these definitions with your permission logic if you need. In this way, you have 2 levels of permission: device level (whether such capability exists at all) and role/subscription level (whether a user has the right to do this). But be careful with the order of rules. See [Combining Abilities][combining-abilities] for details.
3333

34-
The better way would be to create 2 instances of `Ability`: 1 for hardware capabilities another for permission based system and then use them together:
34+
The better way would be to create 2 functions which defines:
35+
* hardware capabilities
36+
* and another for permission based system
37+
38+
Hardware should forbid user to do allowed action if it doesn't support that action. That means hardware permissions need to be defined using `cannot` DSL function
3539

3640
```js
37-
const hardwareAbility = AbilityBuilder.define(can => {
38-
if (capabilities.version >= 10) {
39-
can('manage', 'Wifi')
41+
function hardwarePermissions(capabilities) {
42+
const { cannot, rules } = AbilityBuilder.extract()
43+
44+
if (capabilities.version < 10) {
45+
cannot('manage', 'Wifi').because('Device does not support Wifi')
4046
}
4147

42-
can(....)
43-
....
44-
})
48+
cannot(...)
49+
50+
return rules
51+
}
52+
```
53+
54+
User permissions can be defined as usually:
55+
56+
```js
57+
function userPermissions(user) {
58+
const { can, rules } = AbilityBuilder.extract()
4559

46-
const userAbility = AbilityBuilder.define(can => {
47-
if (user.isAdmin) {
60+
if (user.role === 'admin') {
4861
can('manage', 'all')
4962
} else {
5063
can('read', 'all')
5164
}
52-
})
5365

54-
if (hardwareAbility.can('manage', 'Wifi') && userAbility.can('manage', 'Wifi')) {
55-
// show wifi settings page
66+
return rules
5667
}
5768
```
5869

70+
Now, we can merge them and create `Ability` instance. As hardware capabilities should override role permissions, it should be added at the end (rules order matters, see [Combining Abilities][combining-abilities] for details)
71+
72+
```js
73+
// `capabilities` is an object, represents hardware capabilities, usually provided by hardware API
74+
// `user` is an object, represents information about user details, usually provided by server API
75+
76+
const rules = userPermissions(user)
77+
.concat(hardwarePermissions(capabilities))
78+
79+
const ability = new Ability(rules)
80+
81+
ability.can('manage', 'Wifi')
82+
```
83+
5984
## Feature flags
6085

6186
Also you can use CASL to define feature flags and run [A/B testing](https://en.wikipedia.org/wiki/A/B_testing) for new features.

0 commit comments

Comments
 (0)