Skip to content

Commit babc4d5

Browse files
authored
Merge pull request #10409 from marmelab/update-rbac-documentation
[Doc] Update Access Control instructions following ra-rbac update
2 parents 307c293 + 1a96836 commit babc4d5

17 files changed

+1886
-1199
lines changed

docs/AccordionForm.md

Lines changed: 329 additions & 42 deletions
Large diffs are not rendered by default.

docs/AuthRBAC.md

Lines changed: 245 additions & 824 deletions
Large diffs are not rendered by default.

docs/Buttons.md

Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,80 @@ To override the style of all instances of `<Button>` using the [application-wide
568568

569569
## `<CloneButton>`
570570

571+
The `<CloneButton>` can be added anywhere there is a `RecordContext` to redirect users to the record's resource create page. The create page form will be prefilled with the record values (except the `id`).
572+
573+
### Usage
574+
575+
`<CloneButton>` reads the current resource from `ResourceContext`, so in general it doesn't need any props:
576+
577+
```jsx
578+
import { CloneButton, TopToolbar, List } from 'react-admin';
579+
580+
const PostList = () => (
581+
<List>
582+
<TextField source="title" />
583+
<CloneButton />
584+
</List>
585+
);
586+
```
587+
588+
`<CloneButton>` is based on react-admin's base `<Button>`, so it's responsive, accessible, and the label is translatable.
589+
590+
### Props
591+
592+
| Prop | Required | Type | Default | Description |
593+
| ------------- | -------- | --------------- | ------------------ | -------------------------------------------- |
594+
| `resource` | Optional | `string` | - | Target resource, e.g. 'posts' |
595+
| `label` | Optional | `string` | 'ra.action.create' | label or translation message to use |
596+
| `icon` | Optional | `ReactElement` | - | iconElement, e.g. `<CommentIcon />` |
597+
| `scrollToTop` | Optional | `boolean` | `true` | Scroll to top after link |
598+
599+
It also supports [all the other `<Button>` props](#button).
600+
601+
### Access Control
602+
603+
If you want to control whether this button should be displayed based on users permissions, use the `<CloneButton>` exported by the `@react-admin/ra-rbac` Enterprise package.
604+
605+
```diff
606+
-import { CloneButton } from 'react-admin';
607+
+import { CloneButton } from '@react-admin/ra-rbac';
608+
```
609+
610+
This component adds the following [RBAC](./AuthRBAC.md) controls:
611+
612+
- It will only render if the user has the `'clone'` permission on the current resource.
613+
614+
```js
615+
{ action: "clone", resource: [current resource] }
616+
```
617+
618+
Here is an example of how to use the `<CloneButton>` with RBAC:
619+
620+
```tsx
621+
import { Edit, TopToolbar } from 'react-admin';
622+
import { CloneButton } from '@react-admin/ra-rbac';
623+
624+
const PostEditActions = () => (
625+
<TopToolbar>
626+
<CloneButton />
627+
</TopToolbar>
628+
);
629+
630+
export const PostEdit = () => (
631+
<Edit actions={<PostEditActions />}>
632+
{/* ... */}
633+
</Edit>
634+
);
635+
```
636+
637+
This component accepts additional props:
638+
639+
| Prop | Required | Type | Default | Description |
640+
| -------------------- | -------- | ----------------- | ---------- | ---------------------------------------------------------------------- |
641+
| `accessDenied` | Optional | ReactNode | null | The content to display when users don't have the `'clone'` permission |
642+
| `action` | Optional | String | `"clone"` | The action to call `authProvider.canAccess` with |
643+
| `authorizationError` | Optional | ReactNode | null | The content to display when an error occurs while checking permission |
644+
571645
## `<CreateButton>`
572646

573647
Opens the Create view of the current resource:
@@ -942,6 +1016,58 @@ export const PostList = () => (
9421016

9431017
**Tip**: If you are looking for an `<ImportButton>`, check out this third-party package: [benwinding/react-admin-import-csv](https://github.com/benwinding/react-admin-import-csv).
9441018

1019+
### Access Control
1020+
1021+
If you want to control whether this button should be displayed based on users permissions, use the `<ExportButton>` exported by the `@react-admin/ra-rbac` Enterprise package.
1022+
1023+
```diff
1024+
-import { ExportButton } from 'react-admin';
1025+
+import { ExportButton } from '@react-admin/ra-rbac';
1026+
```
1027+
1028+
This component adds the following [RBAC](./AuthRBAC.md) controls:
1029+
1030+
- It will only render if the user has the `'export'` permission on the current resource.
1031+
1032+
```js
1033+
{ action: "export", resource: [current resource] }
1034+
```
1035+
1036+
- It will only export the fields the user has the `'read'` permission on.
1037+
1038+
```js
1039+
{ action: "read", resource: `${resource}.${source}` }
1040+
```
1041+
1042+
Here is an example usage:
1043+
1044+
```jsx
1045+
import { CreateButton, TopToolbar } from 'react-admin';
1046+
import { ExportButton } from '@react-admin/ra-rbac';
1047+
1048+
const PostListActions = () => (
1049+
<TopToolbar>
1050+
<PostFilter context="button" />
1051+
<CreateButton />
1052+
<ExportButton />
1053+
</TopToolbar>
1054+
);
1055+
1056+
export const PostList = () => (
1057+
<List actions={<PostListActions />}>
1058+
...
1059+
</List>
1060+
);
1061+
```
1062+
1063+
This component accepts additional props:
1064+
1065+
| Prop | Required | Type | Default | Description |
1066+
| -------------------- | -------- | ----------------- | ---------- | ---------------------------------------------------------------------- |
1067+
| `accessDenied` | Optional | ReactNode | null | The content to display when users don't have the `'export'` permission |
1068+
| `action` | Optional | String | `"export"` | The action to call `authProvider.canAccess` with |
1069+
| `authorizationError` | Optional | ReactNode | null | The content to display when an error occurs while checking permission |
1070+
9451071
## `<FilterButton>`
9461072

9471073
This button is an internal component used by react-admin in [the Filter button/form combo](./FilteringTutorial.md#the-filter-buttonform-combo).

docs/Create.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -701,10 +701,20 @@ export const BookCreate = () => {
701701
};
702702
```
703703

704-
## Security
704+
## Anonymous Access
705705

706706
The `<Create>` component requires authentication and will redirect anonymous users to the login page. If you want to allow anonymous access, use the [`disableAuthentication`](#disableauthentication) prop.
707707

708+
```jsx
709+
const PostCreate = () => (
710+
<Create disableAuthentication>
711+
...
712+
</Create>
713+
);
714+
```
715+
716+
## Access Control
717+
708718
If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<Create>` will only render if the user has the "create" access to the related resource.
709719

710720
For instance, for the `<PostCreate>`page below:

docs/Datagrid.md

Lines changed: 127 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1074,48 +1074,6 @@ Additionally, `<DatagridAG>` is compatible with the [Enterprise version of ag-gr
10741074

10751075
Check [the `<DatagridAG>` documentation](./DatagridAG.md) for more details.
10761076

1077-
## Fields And Permissions
1078-
1079-
You might want to display some fields only to users with specific permissions. Use the `usePermissions` hook to get the user permissions and hide Fields accordingly:
1080-
1081-
{% raw %}
1082-
```tsx
1083-
import { List, Datagrid, TextField, TextInput, ShowButton, usePermissions } from 'react-admin';
1084-
1085-
const getUserFilters = (permissions) => ([
1086-
<TextInput label="user.list.search" source="q" alwaysOn />,
1087-
<TextInput source="name" />,
1088-
permissions === 'admin' ? <TextInput source="role" /> : null,
1089-
].filter(filter => filter !== null)
1090-
);
1091-
1092-
export const UserList = ({ permissions, ...props }) => {
1093-
const { permissions } = usePermissions();
1094-
return (
1095-
<List
1096-
{...props}
1097-
filters={getUserFilters(permissions)}
1098-
sort={{ field: 'name', order: 'ASC' }}
1099-
>
1100-
<Datagrid>
1101-
<TextField source="id" />
1102-
<TextField source="name" />
1103-
{permissions === 'admin' && <TextField source="role" />}
1104-
{permissions === 'admin' && <EditButton />}
1105-
<ShowButton />
1106-
</Datagrid>
1107-
</List>
1108-
)
1109-
};
1110-
```
1111-
{% endraw %}
1112-
1113-
Note how the `permissions` prop is passed down to the custom `filters` component to allow Filter customization, too.
1114-
1115-
It's up to your `authProvider` to return whatever you need to check roles and permissions inside your component. Check [the authProvider documentation](./Authentication.md) for more information.
1116-
1117-
**Tip**: The [ra-rbac module](./AuthRBAC.md#datagrid) provides a wrapper for the `<Datagrid>` with built-in permission check for columns.
1118-
11191077
## Standalone Usage
11201078

11211079
You can use the `<Datagrid>` component to display data that you've fetched yourself. You'll need to pass all the props required for its features:
@@ -1386,3 +1344,130 @@ export const PostList = () => (
13861344
</List>
13871345
);
13881346
```
1347+
1348+
## Access Control
1349+
1350+
If you need to hide some columns based on a set of permissions, use the `<Datagrid>` component from the `@react-admin/ra-rbac` package.
1351+
1352+
```diff
1353+
-import { Datagrid } from 'react-admin';
1354+
+import { Datagrid } from '@react-admin/ra-rbac';
1355+
```
1356+
1357+
This component adds the following [RBAC](./AuthRBAC.md) controls:
1358+
1359+
- Users must have the `'read'` permission on a resource column to see it in the export:
1360+
1361+
```jsx
1362+
{ action: "read", resource: `${resource}.${source}` }.
1363+
// or
1364+
{ action: "read", resource: `${resource}.*` }.
1365+
```
1366+
1367+
- Users must have the `'delete'` permission on the resource to see the `<BulkExportButton>`.
1368+
1369+
- The default `rowClick` depends on the user permissions:
1370+
- `"edit"` if the user can access the current resource with the `edit` action
1371+
- `"show"` if the user can access the current resource with the `show` action
1372+
- empty otherwise
1373+
1374+
Here is an example of `<Datagrid>` with RBAC:
1375+
1376+
```tsx
1377+
import { canAccessWithPermissions, List, Datagrid } from '@react-admin/ra-rbac';
1378+
import {
1379+
ImageField,
1380+
TextField,
1381+
ReferenceField,
1382+
NumberField,
1383+
} from 'react-admin';
1384+
1385+
const authProvider = {
1386+
// ...
1387+
canAccess: async ({ action, record, resource }) =>
1388+
canAccessWithPermissions({
1389+
permissions: [
1390+
{ action: 'list', resource: 'products' },
1391+
{ action: 'read', resource: 'products.thumbnail' },
1392+
{ action: 'read', resource: 'products.reference' },
1393+
{ action: 'read', resource: 'products.category_id' },
1394+
{ action: 'read', resource: 'products.width' },
1395+
{ action: 'read', resource: 'products.height' },
1396+
{ action: 'read', resource: 'products.price' },
1397+
{ action: 'read', resource: 'products.description' },
1398+
// { action: 'read', resource: 'products.stock' },
1399+
// { action: 'read', resource: 'products.sales' },
1400+
// { action: 'delete', resource: 'products' },
1401+
{ action: 'show', resource: 'products' },
1402+
],
1403+
action,
1404+
record,
1405+
resource
1406+
}),
1407+
};
1408+
1409+
const ProductList = () => (
1410+
<List>
1411+
{/* The datagrid has no bulk actions as the user doesn't have the 'delete' permission */}
1412+
<Datagrid>
1413+
<ImageField source="thumbnail" />
1414+
<TextField source="reference" />
1415+
<ReferenceField source="category_id" reference="categories">
1416+
<TextField source="name" />
1417+
</ReferenceField>
1418+
<NumberField source="width" />
1419+
<NumberField source="height" />
1420+
<NumberField source="price" />
1421+
<TextField source="description" />
1422+
{/** These two columns are not visible to the user **/}
1423+
<NumberField source="stock" />
1424+
<NumberField source="sales" />
1425+
</Datagrid>
1426+
</List>
1427+
);
1428+
```
1429+
1430+
**Tip**: Adding the 'read' permission on the resource itself doesn't grant the 'read' permission on the columns. If you want a user to see all possible columns, add the 'read' permission on columns using a wildcard:
1431+
1432+
```jsx
1433+
{ action: "read", resource: "products.*" }.
1434+
```
1435+
1436+
Fow simple cases, you can also use [the `useCanAccess` hook](./useCanAccess.md) to check whether users have access to a field:
1437+
1438+
{% raw %}
1439+
```tsx
1440+
import { List, Datagrid, TextField, TextInput, ShowButton, useCanAccess } from 'react-admin';
1441+
1442+
const getUserFilters = (canAccessRole) => ([
1443+
<TextInput label="user.list.search" source="q" alwaysOn />,
1444+
<TextInput source="name" />,
1445+
canAccessRole ? <TextInput source="role" /> : null,
1446+
].filter(filter => filter !== null)
1447+
);
1448+
1449+
export const UserList = ({ permissions, ...props }) => {
1450+
const { canAccess, error, isPending } = useCanAccess({
1451+
resource: 'users.role',
1452+
action: 'read'
1453+
});
1454+
return (
1455+
<List
1456+
{...props}
1457+
filters={getUserFilters(canAccess)}
1458+
sort={{ field: 'name', order: 'ASC' }}
1459+
>
1460+
<Datagrid>
1461+
<TextField source="id" />
1462+
<TextField source="name" />
1463+
{canAccess ? <TextField source="role" /> : null}
1464+
<EditButton />
1465+
<ShowButton />
1466+
</Datagrid>
1467+
</List>
1468+
)
1469+
};
1470+
```
1471+
{% endraw %}
1472+
1473+
Note how the `canAccess` value is passed down to the custom `filters` component to allow Filter customization, too.

docs/Edit.md

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -981,10 +981,20 @@ export const BookEdit = () => {
981981
};
982982
```
983983

984-
## Security
984+
## Anonymous Access
985985

986986
The `<Edit>` component requires authentication and will redirect anonymous users to the login page. If you want to allow anonymous access, use the [`disableAuthentication`](#disableauthentication) prop.
987987

988+
```jsx
989+
const PostEdit = () => (
990+
<Edit disableAuthentication>
991+
...
992+
</Edit>
993+
);
994+
```
995+
996+
## Access Control
997+
988998
If your `authProvider` implements [Access Control](./Permissions.md#access-control), `<Edit>` will only render if the user has the "edit" access to the related resource.
989999

9901000
For instance, for the `<PostEdit>`page below:
@@ -1012,4 +1022,4 @@ const PostEdit = () => (
10121022

10131023
Users without access will be redirected to the [Access Denied page](./Admin.md#accessdenied).
10141024

1015-
**Note**: Access control is disabled when you use [the `disableAuthentication` prop](#disableauthentication).
1025+
**Note**: Access control is disabled when you use [the `disableAuthentication` prop](#disableauthentication).

0 commit comments

Comments
 (0)