aor-permissions
This project is discontinued. Its features have been merged in admin-on-rest 1.3.0. See admin-on-rest documentation
A component for Admin-on-rest allowing to switch views depending on user roles.
Installation
Install with:
npm install --save aor-permissions
or
yarn add aor-permissions
Usage
First, the authClient must handle a new type: AUTH_GET_PERMISSIONS
.
Here is a naive implementation using localstorage:
// in authClient.jsimport AUTH_LOGIN AUTH_LOGOUT AUTH_CHECK AUTH_ERROR from 'admin-on-rest';import AUTH_GET_PERMISSIONS from 'aor-permissions';import decode from 'jsonwebtoken'; type params if type === AUTH_LOGIN const username password = params; const request = 'https://mydomain.com/authenticate' method: 'POST' body: JSON headers: 'Content-Type': 'application/json' return ; // ... usual authClient code if type === AUTH_GET_PERMISSIONS return Promise; ;
Then, you may use the SwitchPermissions
and Permission
components:
Simple permissions check
// In products.jsimport SwitchPermissions Permission from 'aor-permissions';import authClient from '../authClient'; // ...other views as usual (List, Create, etc.) // Use this ProductEdit component as usual in your resource declarationconst ProductEdit = <SwitchPermissions = > <Permission ="role1"> <Edit > /* Usual layout component */ </Edit> </Permission> <Permission => <Edit > /* Usual layout component */ </Edit> </Permission> <Permission = > <Edit > /* Usual layout component */ </Edit> </Permission> </SwitchPermissions>;
Permissions check depending on the resource/record
// In products.jsimport SwitchPermissions Permission from 'aor-permissions';import authClient from '../authClient'; // ...other views as usual (List, Create, etc.) const checkUserCanEdit = params const user = paramspermissions; // This is the result of the `authClient` call with type `AUTH_GET_PERMISSIONS` const resource = paramsresource; // The resource, eg: 'posts' const record = paramsrecord; // The current record (only supplied for Edit) // Only user with admin role can edit the posts of the 'announcements' category if recordcategory === 'announcement' && userrole === 'admin' return true; return false; // Use this PostEdit component as usual in your resource declaration// Note that in order to get the record, we must have the SwitchPermissions component inside the Edit componentconst PostEdit = <Edit > <SwitchPermissions = > <Permission => /* Usual layout component */ </Permission> <Permission => /* Usual layout component */ </Permission> </SwitchPermissions> </Edit>;
Protect access to resources
import Admin from 'aor-permissions';import Resource from 'admin-on-rest';import restClient from '../restClient';import authClient from '../authClient';import PostList PostEdit PostCreate from './posts'; const resolveAccessToPosts = resource permissions exact value // value = the requested permissions specified in the `permissions` prop (eg `admin`). May be undefined // resource = the requested resource (eg `posts`) // exact = the value of the `exact` prop // permissions = the result of the authClient call; const resolveEditAccess = resource permissions exact value // value = the requested permissions specified in the `permissions` prop (eg `admin`). May be undefined // resource = the requested resource (eg `posts`) // exact = the value of the `exact` prop // permissions = the result of the authClient call; const App = <Admin = => <Resource ="posts" = = = ="admin" = = ="admin" = /> </Admin>;
API
SwitchPermissions
The SwitchPermissions
component requires an authClient
prop which accepts the same (authClient) as in Admin-on-rest. However, this client must be able to handle the new AUTH_GET_PERMISSIONS
type.
It also accepts two optional props:
loading
: A component to display while checking for permissions. It defaults to the Material-UI LinearProgress inindeterminate
mode.notFound
: A component to display when no match was found while checking the permissions. Default tonull
.
The SwitchPermissions
component only accepts Permission
components as children. They are used to map a permission to a view.
Permission
The Permission
component requires either a value
with the permissions to check (could be a role, an array of rules, etc) or a resolve
function.
If both are specified, only resolve
will be used.
You can pass anything as children for this component: a view (List, Create, Edit), an input, a React node, whatever.
Using the value prop
Permissions matches differently depending on the value
type and the authClient result type.
An additional exact
prop may be specified on the Permission
component depending on your requirements.
The following table shows how permissions are resolved:
permissions | authClient result | exact | resolve |
---|---|---|---|
single value | single value | permissions must equal authClient result | |
single value | array | authClient result must contain permissions | |
array | single value | permissions must contain authClient result | |
array | array | false |
at least one value of permissions must be present in authClient result |
array | array | true |
all values in permissions must be present in authClient result |
Using the resolve prop
The function specified for resolve
may return true
or false
directly or a promise resolving to either true
or false
. It will be called with an object having the following properties:
permissions
: the result of theauthClient
call.resource
: the resource being checked (eg:products
,posts
, etc.)value
: the value of thevalue
propexact
: the value of theexact
proprecord
: Only when inside anEdit
component, the record being edited
If multiple matches are found, the first one will be applied.
WithPermission
A simpler component which will render its children only if its permissions are matched. For example, in a custom Menu:
import React from 'react';import Link from 'react-router-dom';import MenuItem from 'material-ui/MenuItem';import SettingsIcon from 'material-ui/svg-icons/action/settings';import WithPermission from 'aor-permissions';import authClient from './authClient'; const Menu = onMenuTap logout <div> /* Other menu items */ <WithPermission = ="admin"> <MenuItem = ="Configuration" = = /> </WithPermission> logout </div>; ;
The WithPermission
component accepts the following props:
authClient
: the same (authClient) as in Admin-on-rest. However, this client must be able to handle the newAUTH_GET_PERMISSIONS
type.value
: the permissions to check (could be a role, an array of rules, etc)resolve
: a function called to resolve the permissions. (same asPermission
)
You can pass anything as children for this component: a view (List, Create, Edit), an input, a React node, whatever.
AuthProvider
Requiring and specifying the authClient
for each SwitchPermissions
and WithPermission
components could be cumbersome. That's why we also provided an AuthProvider
component.
It must enclose the Admin component.
It accepts a single prop: authClient
.
import Admin Resource from 'admin-on-rest';import AuthProvider from 'aor-permissions';import authClient from './authClient'; const App = <AuthProvider => <Admin> /* Usual Resource components */ </Admin> </AuthProvider>
Admin
This component can be used instead of the default Admin
component from admin-on-rest
.
It allows to define permissions on each resource and for each resource's view.
It accepts the following props:
permissions
: to define the permissions required for the whole resourceresolve
: function called to check whether permissions for the whole resource are okexact
: Boolean for exact match (useful whenpermissions
is an array)
If defined, the resolve
function will be called with an object containing the following properties:
permissions
: the result of theauthClient
call.value
: the value of thepermissions
prop: the requested permissionsexact
: the value of theexact
prop
Additionnaly, the Admin
components accepts for each view (list, create, edit and remove) the same three props prefixed with the view's name. For example: listPermissions
, listResolve
and listExact
.
Note: when using this custom Admin
component, there's no need to use the AuthProvider
too as it will be added automatically.
Contributing
Run the tests with this command:
make test
Coverage data is available in ./coverage
after executing make test
.
An HTML report is generated in ./coverage/lcov-report/index.html
.