This repository showcase how we can implement a permissions based system in a SPA react application.
It is bootstraped with the react-ts vite template, so it is only client side. It could maybe work with SSR, but I haven't tried it.
If you find something that could be improved, you're more than welcome to open an issue or a PR.
I'm by no means an expert, just wanted to share my implementation.
There is two main components to this implementation, the useAuth.tsx hook and the permission-gate.tsx component.
In this file you have a react context that will hold the user informations, some utility functions and the useAuth hook.
- You have the
login()function that will set currentUser in the state, stored in the localStorage withZustand, and redirect the dashboard page. - You have the
logout()function that remove the currentUser in the state and redirect to the login page. - The exposed
currentUserstate that contains the user informations. - A
hasPermissions()function that will check if the user has the required permissions.- Note: This function also check if the user has the
adminpermission, which will give him access to everything.
- Note: This function also check if the user has the
The user permissions are encrypted and decrypted with the crypto-js library, to not have the permissions in plain text in the localStorage (note: the encryptPassPhrase should be stored somewhere else).
All the functions and the currentUser state are memoized and exposed with the useAuth hook, that use the react context.
You can use the useAuth hook like this:
const { currentUser, login, logout, hasPermissions } = useAuth();
if (currentUser?.name === 'admin') {
// do something
}
if (hasPermissions(['admin'])) {
// do something
}
//etc...This component is a wrapper that takes an array of permissions and validate if the user has the required permissions to access the wrapped component by calling the hasPermissions() function from the useAuth hook.
It also take an actionType, that will determine which action to take if the user doesn't have the required permissions.
actionType="REDIRECT"will redirect the user to the dashboard page (can be changed to use a homePage that is linked to the user).actionType="HIDE"will return an empty fragment, so the user won't see anything.actionType="DISABLE"will loop through all the children and disable them with thedisabledprop.- Note 1: This will only work with components that accept the
disabledprop. - Note 2: It doesn't recursively loop through the children, so be sure to only have one level of children (could be implemented).
- Note 1: This will only work with components that accept the
You can use this component in two ways:
- As a wrapper around a component, like this:
<PermissionGate permissions={['admin']} actionType="HIDE">
<MyComponent />
</PermissionGate>- As a
Routeelement (fromreact-router-dom), like this:
{
element: <PermissionsGate permissions={['dashboardPage']} actionType="REDIRECT" />,
children: [
{
path: 'dashboard',
element: <Dashboard />
}
]
}On top of the permissions implementation, there is also two layouts that are used to restrict access to some pages based if the user is logged in or not.
Those layouts use the Navigate and Outlet from react-router-dom, so you'll need to use the Route component from react-router-dom to use them.
public-layout.tsxredirect to the dashboard page user is logged inprotected-layout.tsxredirect to the login page user is not logged in
You have three users to choose from on the login page, which all have different permissions. See the USERS constant in the config.ts file to see the permissions for each user.
- In the
main.tsxfile, you have some exemples of how to use thePermissionGatecomponent withRoute, and how to use thepublic-layoutandprotected-layoutcomponents. - In the
dashboard.tsxpage and in thenavbar.tsxcomponent, you have some exemples of how to use thePermissionGatecomponent as a wrapper around a component. - The
user.tsxpage is only there to show the redirection when the user doesn't have the required permissions.
- Vite for the template and build tool
- React Router for routing
- Zustand for state management with localStorage (currentUser)
- TailwindCSS for quick and easy styling
- shadcn/ui for the beautiful UI components
- ESLint for code linting and Prettier for code formatting
- CryptoJS for encrypting and decrypting the user permissions
git clone
cd react-permissions-implementation
pnpm install
pnpm run dev