Skip to content

Commit d25a8d3

Browse files
committed
Improve authProvider part
1 parent 62ac689 commit d25a8d3

1 file changed

Lines changed: 43 additions & 9 deletions

File tree

docs/AuthRBAC.md

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ npm install --save @react-admin/ra-rbac
6868
yarn add @react-admin/ra-rbac
6969
```
7070

71+
Make sure you [enable auth features](https://marmelab.com/react-admin/Authentication.html#enabling-auth-features) by setting an `<Admin authProvider>`, and [disable anonymous access](https://marmelab.com/react-admin/Authentication.html#disabling-anonymous-access) by adding the `<Admin requireAuth>` prop. This will ensure that react-admin waits for the `authProvider` response before rendering anything.
72+
7173
**Tip**: ra-rbac is part of the [React-Admin Enterprise Edition](https://marmelab.com/ra-enterprise/), and hosted in a private npm registry. You need to subscribe to one of the Enterprise Edition plans to access this package.
7274

7375
## Concepts
@@ -141,6 +143,10 @@ const corrector123Role = [
141143
];
142144
```
143145

146+
**Tip**: The _order_ of permissions isn't significant. As soon as at least one permission grants access to an action on a resource, ra-rbac grant access to it - unless there is an [explicit deny](#explicit-deny).
147+
148+
The RBAC system relies on *permissions* only. It's the `authProvider`'s responsibility to map roles to permissions. See the [`authProvider` Methods](#authprovider-methods) section for details.
149+
144150
### Record-Level Permissions
145151

146152
By default, a permission applies to all records of a resource.
@@ -182,7 +188,7 @@ const allProductsButStock = [
182188

183189
## `authProvider` Methods
184190

185-
Ra-rbac builds up on react-admin's `authProvider` API. It precises the return format of the `getPermissions()` method which must return a promise for object containing `permissions` (an array of permissions).
191+
Ra-rbac builds up on react-admin's `authProvider` API. It precises the return format of the `getPermissions()` method which must return a promise for an array of permissions objects.
186192

187193
```jsx
188194
const authProvider = {
@@ -193,17 +199,27 @@ const authProvider = {
193199
};
194200
```
195201

196-
For every restricted resource, ra-rbac calls `authProvider.getPermissions()` to get the permissions.
202+
For every restricted resource, ra-rbac calls `authProvider.getPermissions()` to get the permissions. In practice, the permissions are usually returned upon login rather than in the `authProvider` code. The authProvider stores the permissions in memory or localStorage.
197203

198-
For the example dataProvider above, this translates to the following set of permissions:
204+
`authProvider.getPermissions()` doesn't return roles - only permissions. Usually, the role definitions are committed with the application code, as a constant. The roles of the current user are fetched at login, and the permissions are computed from the roles and the role definitions.
199205

200-
`{ action: ["read", "write"], resource: "users", record: { "id": "123" } }`
206+
You can use the `getPermissionsFromRoles` helper in the `authProvider` to compute the permissions that the user has based on their permissions. This function takes an object as argument with the following fields:
201207

202-
In practice, the permissions are usually returned upon login rather than in the `authProvider` code. The authProvider stores the permissions in memory or localStorage. The `authProvider.getPermissions()` method only retrieve the permissions from localStorage.
208+
- `roleDefinitions`: a static object containing the role definitions for each role
209+
- `userRoles` _(optional)_: an array of roles (admin, reader...) for the current user
210+
- `userPermissions` _(optional)_: an array of permissions for the current user, to be added to the permissions computed from the roles
203211

204-
```jsx
212+
Here is an example `authProvider` implementation following this pattern:
213+
214+
```tsx
215+
import { getPermissionsFromRoles } from '@react-admin/ra-rbac';
216+
217+
const roleDefinitions = {
218+
admin: [{ action: '*', resource: '*' }],
219+
reader: [{ action: 'read', resource: '*' }],
220+
};
205221
const authProvider = {
206-
login: ({ username, password }) => {
222+
login: ({ username, password }) => {
207223
const request = new Request('https://mydomain.com/authenticate', {
208224
method: 'POST',
209225
body: JSON.stringify({ username, password }),
@@ -217,12 +233,30 @@ const authProvider = {
217233
return response.json();
218234
})
219235
.then(data => {
220-
localStorage.setItem('permissions', JSON.stringify(data.permissions));
236+
// data is like
237+
// {
238+
// "id": 123,
239+
// "fullName": "John Doe",
240+
// "permissions": [
241+
// { action: ["read", "write"], resource: "users", record: { id: "123" } },
242+
// ]
243+
// "roles": ["admin", "reader"],
244+
// }
245+
const permissions = getPermissionsFromRoles({
246+
roleDefinitions,
247+
userPermissions: data.permissions,
248+
userRoles: data.roles,
249+
});
250+
localStorage.setItem(
251+
'permissions',
252+
JSON.stringify(permissions)
253+
);
221254
});
222255
},
223256
// ...
224257
getPermissions: () => {
225-
return JSON.parse(localStorage.getItem("permissions"));
258+
const permissions = JSON.parse(localStorage.getItem('permissions'));
259+
return Promise.resolve(permissions);
226260
},
227261
};
228262
```

0 commit comments

Comments
 (0)