canAccess
This helper function, part of the ra-rbac module, can check if the current permissions allow the user to execute an action on a resource (and optionally a record). It requires the user permissions
array, so it must be used in conjunction with usePermissions
.
Usage
canAccess
expects an object { permissions, resource, action, record }
as parameter, and returns a boolean.
import { usePermissions, EditButton } from 'react-admin';
import { canAccess } from '@react-admin/ra-rbac';
const PostEditButton = () => {
const { isLoading, permissions } = usePermissions();
if (isLoading) return null;
if (canAccess({ permissions, action: "edit", resource: "posts" })) {
return <EditButton />;
} else {
return null;
}
};
With the following permissions:
console.log(await authProvider.getPermissions())
// [
// { action: ['read', 'edit', 'create', 'delete'], resource: 'posts' },
// ]
The PostEditButton
component will render the <EditButton>
.
Tip: canAccess
is mostly useful when you already have the permissions at hand. If you need to fetch the permissions every time you call canAccess
, prefer using the useCanAccess
hook or the <IfCanAccess>
component instead.
Parameters
canAccess
expects a single parameter object with the following properties:
Name | Required | Type | Default | Description |
---|---|---|---|---|
permissions |
Required | Permissions[] |
- | The permissions array, as returned by the usePermissions hook. |
resource |
Required | string |
- | The resource to check, e.g. ‘users’, ‘comments’, ‘posts’, etc. |
action |
Optional | string |
- | The action to check, e.g. ‘read’, ‘list’, ‘export’, ‘delete’, etc. |
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" } |
action
Specify the action you want to check.
const permissions = [
{ resource: 'posts', action: ['read', 'edit', 'create'] },
];
canAccess({ permissions, resource: 'posts', action: 'read' }); // true
canAccess({ permissions, resource: 'posts', action: 'edit' }); // true
canAccess({ permissions, resource: 'posts', action: 'create' }); // true
canAccess({ permissions, resource: 'posts', action: 'delete' }); // false
canAccess({ permissions, resource: 'posts', action: 'export' }); // false
You don’t have to provide an action
if you just want to know whether users can access the CRUD pages of a resource. This is useful to leverage canAccess
in an <Admin>
component children function:
import { Admin, Resource, ListGuesser, EditGuesser } from 'react-admin';
import { canAccess } from '@react-admin/ra-rbac';
import { dataProvider } from './dataProvider';
const authProvider = {
checkAuth: () => Promise.resolve(),
login: () => Promise.resolve(),
logout: () => Promise.resolve(),
checkError: () => Promise.resolve(),
getPermissions: () =>
Promise.resolve([
{ action: 'list', resource: 'products' },
{ action: 'edit', resource: 'categories' },
]),
};
export const MyApp = () => (
<Admin authProvider={authProvider} dataProvider={dataProvider}>
{(permissions: Permissions) => (
<>
{canAccess({ permissions, resource: 'products' }) ? (
<Resource name="products" list={ListGuesser} />
) : null}
{canAccess({ permissions, resource: 'categories' }) ? (
<Resource name="categories" list={ListGuesser} edit={EditGuesser} />
) : null}
{canAccess({ permissions, resource: 'commands' }) ? (
<Resource name="commands" list={ListGuesser} />
) : null}
</>
)}
</Admin>
);
In this example, users will see the products list and will be able to click on its category link to edit the category. However, they won’t see the categories list nor the commands list.
Note that ra-rbac’s <Resource>
component does this check automatically, so you don’t actually need to use canAccess
in this case.
import { Admin, ListGuesser, EditGuesser } from 'react-admin'; // do not import Resource here
import { Resource } from '@react-admin/ra-rbac';
import { dataProvider } from './dataProvider';
export const MyApp = () => (
<Admin authProvider={authProvider} dataProvider={dataProvider}>
<Resource name="products" list={ListGuesser} />
<Resource name="categories" list={ListGuesser} edit={EditGuesser} />
<Resource name="commands" list={ListGuesser} />
</Admin>
);
permissions
The permissions
parameter must contain the permissions of the current user. It is usually retrieved using the usePermissions
hook:
const { permissions } = usePermissions();
if (canAccess({ permissions, action: "edit", resource: "posts" })) {
return <EditButton />;
} else {
return null;
}
When the permissions
is null (e.g. if the usePermissions
hook is still loading), canAccess
always returns false
.
resource
The resource
parameter is the resource you want to check. It can be the name of a resource, or the name of a resource field, depending on the granularity you need.
const ProductList = () => {
const { isLoading, permissions } = usePermissions();
if (isLoading) return null;
return (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="reference" />
<TextField source="width" />
<TextField source="height" />
{canAccess({
permissions,
action: 'read',
resource: 'products.price',
}) && <TextField source="price" />}
{/* this column will not render */}
{canAccess({
permissions,
action: 'read',
resource: 'products.stock',
}) && <TextField source="stock" />}
</Datagrid>
</List>
);
};
record
RBAC allows to specify record-level permissions. These permissions are checked when you specify the record
prop.
const permissions = [
{ resource: 'posts', action: 'read', record: { id: 1 } },
];
canAccess({
permissions,
resource: 'posts',
action: 'read',
record: { id: 1, title: 'Lorem Ipsum' },
}); // true
canAccess({
permissions,
resource: 'posts',
action: 'read',
record: { id: 2, title: 'Sit Dolor Amet' },
}); // false
Hiding Columns in a Datagrid
canAccess
is useful to hide restricted elements in the admin, e.g. to hide columns in a datagrid:
import { List, Datagrid, TextField } from 'react-admin';
import { canAccess } from '@react-admin/ra-rbac';
const authProvider = {
checkAuth: () => Promise.resolve(),
login: () => Promise.resolve(),
logout: () => Promise.resolve(),
checkError: () => Promise.resolve(),
getPermissions: () => Promise.resolve({
permissions: [
{ action: 'list', resource: 'products' },
{ action: 'read', resource: 'products.price' },
],
}),
};
const ProductList = () => {
const { isLoading, permissions } = usePermissions();
if (isLoading) return null;
return (
<List>
<Datagrid>
<TextField source="id" />
<TextField source="reference" />
<TextField source="width" />
<TextField source="height" />
{canAccess({
permissions,
action: 'read',
resource: 'products.price',
}) && <TextField source="price" />}
{/* this column will not render */}
{canAccess({
permissions,
action: 'read',
resource: 'products.stock',
}) && <TextField source="stock" />}
</Datagrid>
</List>
);
};
Tip: Ra-rbac actually proposes a <Datagrid>
component that hides columns depending on permissions. Check the RBAC documentation for details.