How to implement role based access control in nodejs express app
Implementing role-based access control (RBAC) involves managing user roles and permissions both on the frontend (React) and backend (Express). Here’s a basic guide on how to implement RBAC in a React and Express application:
Backend (Express)
-
Define Roles and Permissions: Decide on the roles (e.g., admin, user) and their corresponding permissions (e.g., read, write) in your application.
-
User Model: Include role information in your user model. Example using Mongoose:
const mongoose = require('mongoose'); const userSchema = new mongoose.Schema({ username: { type: String, required: true }, email: { type: String, required: true }, password: { type: String, required: true }, role: { type: String, enum: ['user', 'admin'], default: 'user' } }); module.exports = mongoose.model('User', userSchema);
-
Authentication Middleware: Create a middleware to check role-based access:
// middleware/authenticate.js const jwt = require('jsonwebtoken'); function authenticate(role) { return function(req, res, next) { const token = req.header('Authorization'); if (!token) { return res.status(401).json({ message: 'Unauthorized' }); } try { const decoded = jwt.verify(token, process.env.JWT_SECRET); req.user = decoded.user; if (role && req.user.role !== role) { return res.status(403).json({ message: 'Forbidden' }); } next(); } catch (err) { console.error(err); res.status(500).json({ message: 'Server Error' }); } }; } module.exports = authenticate;
-
Route Protection: Protect routes using the authentication middleware:
// routes/secureRoute.js const express = require('express'); const router = express.Router(); const authenticate = require('../middleware/authenticate'); // Route accessible only to admin router.get('/admin', authenticate('admin'), (req, res) => { res.json({ message: 'Admin Route' }); }); // Route accessible to all authenticated users router.get('/user', authenticate(), (req, res) => { res.json({ message: 'User Route' }); }); module.exports = router;
Frontend (React)
-
Store User Role: After successful login, store the user’s role in the frontend (e.g., using Redux, Context API, or local storage).
-
Protect Routes: Create a higher-order component (HOC) or a custom hook to protect routes based on the user's role:
// components/PrivateRoute.js import React from 'react'; import { Route, Redirect } from 'react-router-dom'; const PrivateRoute = ({ component: Component, roles, ...rest }) => ( <Route {...rest} render={props => ( roles.includes(user.role) ? <Component {...props} /> : <Redirect to='/login' /> )} /> ); export default PrivateRoute;
-
Usage: Use the
PrivateRoute
component to protect routes in your application:import React from 'react'; import { BrowserRouter as Router, Route, Switch } from 'react-router-dom'; import PrivateRoute from './components/PrivateRoute'; import AdminPage from './pages/AdminPage'; import UserPage from './pages/UserPage'; const App = () => { return ( <Router> <Switch> <PrivateRoute path="/admin" roles={['admin']} component={AdminPage} /> <PrivateRoute path="/user" roles={['admin', 'user']} component={UserPage} /> <Route path="/login" component={LoginPage} /> <Route path="/" exact component={HomePage} /> </Switch> </Router> ); }; export default App;