<IfCanAccess>
This component, part of the ra-rbac module, renders its child only if the user has the right permissions.
Usage
Wrap the components that you want to add access control to with the <IfCanAccess>
component.
For example, to display action buttons for a company record only if the user has the right permissions:
import { IfCanAccess } from '@react-admin/ra-rbac';
import { Toolbar, DeleteButton, EditButton } from 'react-admin';
const CompanyRecordToolbar = () => (
<Toolbar>
<IfCanAccess action="edit">
<EditButton />
</IfCanAccess>
<IfCanAccess action="delete">
<DeleteButton />
</IfCanAccess>
</Toolbar>
);
With this code and the following user permissions:
console.log(await authProvider.getPermissions())
// [
// { action: ["create", "edit"], resource: "companies" },
// ...
// ];
The CompanyRecordToolbar
component will render the <EditButton>
but not the <DeleteButton>
.
Props
Prop | Required | Type | Default | Description |
---|---|---|---|---|
action |
Required | string |
The action to check, e.g. ‘read’, ‘list’, ‘export’, ‘delete’, etc. | |
resource |
Optional | string |
The resource to check, e.g. ‘users’, ‘comments’, ‘posts’, etc. Falls back to the current resource context if absent. | |
record |
Optional | object |
The record to check. If passed, the child only renders if the user has permissions for that record, e.g. { id: 123, firstName: "John", lastName: "Doe" } |
|
fallback |
Optional | ReactNode |
null |
The element to render when the user does not have the permission. Defaults to null . |
Additional props are passed down to the child element.
action
The action
prop allows you to restrict a component to users who have a permission to use the specified action on the current resource.
For instance, if the user has the following permissions:
console.log(await authProvider.getPermissions())
// [
// { action: ["read", "create", "edit", "export"], resource: "companies" },
// ...
// ];
To display the ExportButton
in a CompanyList
component, you would use:
<IfCanAccess action="export">
<ExportButton />
</IfCanAccess>
resource
By default, <IfCanAccess>
uses the current resource (from the ResourceContext
) to check permissions. You can override this behavior by passing the resource
prop:
<IfCanAccess action="export" resource="companies">
<ExportButton />
</IfCanAccess>
record
RBAC allows to specify record-level permissions. These permissions are triggered when you specify the record
prop.
For example, let’s say a user has the permission to edit a company only if the company is in the same group as the user:
console.log(await authProvider.getPermissions())
// [
// { action: 'edit', resource: "companies', record: { group: 'middle_east' } },
// ];
To display the EditButton
in a CompanyShow
component, you would use:
const EditCompanyButton = () => {
const record = useRecordContext();
return (
<IfCanAccess action="edit" record={record}>
<EditButton />
</IfCanAccess>
);
};
fallback
ra-rbac
shows a Not Found page when users try to access a page they don’t have the permissions for. It is considered good security practice not to disclose to a potentially malicious user that a page exists if they are not allowed to see it.
However, should you prefer to show an ‘Access Denied’ screen in those cases, you can do so by specifying a fallback
component in <IfCanAccess>
:
// in src/posts/PostCreate.tsx
import { Create, SimpleForm, TextInput } from 'react-admin';
import { IfCanAccess } from '@react-admin/ra-rbac';
import { Navigate } from 'react-router-dom';
export const PostCreate = () => (
<IfCanAccess action="create" fallback={<Navigate to="/access-denied" />}>
<Create>
<SimpleForm>
<TextInput source="title" />
</SimpleForm>
</Create>
</IfCanAccess>
);
Tip: This example uses a Navigate
component to redirect to a custom page because you cannot use a Redirect
component in this context. The IfCanAccess
component uses a render prop, and Redirect
only works in the render method of a component.
Note that if you use the fallback
prop for a CRUD page (Create, Edit, List, Show) as above, you must use the <Resource>
component from react-admin
rather than the one from ra-rbac
. This is because ra-rbac
already does the access control check, and would redirect to the Not Found page before the fallback component is rendered.
// In src/App.tsx
import { Admin, CustomRoutes, Resource } from 'react-admin';
import { Route } from 'react-router';
import { dataProvider } from './dataProvider';
import { authProvider } from './authProvider';
import posts from './posts';
const AccessDenied = () => (
<Typography>You don't have the required permissions to access this page.</Typography>
);
export const App = () => (
<Admin dataProvider={dataProvider} authProvider={authProvider}>
<CustomRoutes>
<Route path="access-denied" element={<AccessDenied />} />
</CustomRoutes>
<Resource name="posts" {...posts} />
</Admin>
);