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
currentUser
state 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
admin
permission, 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 thedisabled
prop.- Note 1: This will only work with components that accept the
disabled
prop. - 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
Route
element (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.tsx
redirect to the dashboard page user is logged inprotected-layout.tsx
redirect 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.tsx
file, you have some exemples of how to use thePermissionGate
component withRoute
, and how to use thepublic-layout
andprotected-layout
components. - In the
dashboard.tsx
page and in thenavbar.tsx
component, you have some exemples of how to use thePermissionGate
component as a wrapper around a component. - The
user.tsx
page 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