🔐Implementing Role-Based Access Control (RBAC) in Node.js Express
Role-based access control (RBAC) is an essential security feature in modern web applications. It ensures that different users have varying levels of access, depending on their roles, to protect sensitive data and functionality. In this article, we will delve into how to implement RBAC in Node.js Express applications.
Introduction to RBAC
RBAC is a security model that restricts access to resources and actions based on a user's role. It separates the management of user permissions from individual users, making it easier to maintain and scale your application. By assigning roles to users, you can control who can access specific resources and perform certain actions in your application.
Setting up the Project
Before diving into RBAC implementation, let's set up a new Node.js Express project:
$ mkdir rbac-node-express
$ cd rbac-node-express
$ npm init -y
$ npm install express body-parser mongoose
$ npm install --save-dev nodemon
Create a .env
file to store environment variables, and include the following content:
PORT=3000
MONGODB_URI=mongodb://localhost:27017/rbac-node-express
Update the package.json
file to include the following script:
{
...
"scripts": {
"start": "nodemon index.js"
},
...
}
Now, create an index.js file with the following code:
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
dotenv.config();
const app = express();
app.use(bodyParser.json());
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(() => console.log('Connected to MongoDB'));
app.listen(process.env.PORT, () => {
console.log(`Server running at http://localhost:${process.env.PORT}`);
});
Creating Roles and Permissions
First, define the roles and permissions for your application. Create a roles.js
file and include the following content:
const roles = {
admin: {
can: [
'read',
'write',
'delete',
],
},
editor: {
can: [
'read',
'write',
],
},
viewer: {
can: [
'read',
],
},
};
module.exports = roles;
Here, we've defined three roles: admin
, editor
, and viewer
, each with different permissions.
Defining Middleware for Role-Based Authorization
Now, create a middleware function to check if the user has the required role to access a specific route. Create a new file called roleMiddleware.js and add the following code:
const roles = require('./roles');
const checkRole = (requiredRole) => (req, res, next) => {
const userRole = req.user.role;
if (!roles[userRole].can.includes(requiredRole)) {
return res.status(403).send('Forbidden');
}
next();
};
module.exports = checkRole;
In this code, we import the roles defined earlier and create a checkRole
function that takes the required role as an argument. The middleware function checks if the user's role includes the required permission; if not, it returns a 403 Forbidden status. Otherwise, it proceeds to the next middleware or route handler.
Implementing RBAC in Routes
Now that we have the middleware function in place, we can start implementing RBAC in our application routes. First, create a user.js
file to define a sample user object:
const user = {
name: 'John Doe',
role: 'admin', // Change this value to test different roles
};
module.exports = user;
Next, update your index.js
file to include the following code:
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const dotenv = require('dotenv');
const checkRole = require('./roleMiddleware');
const user = require('./user');
dotenv.config();
const app = express();
app.use(bodyParser.json());
// Simulate user authentication by adding the user object to the request
app.use((req, res, next) => {
req.user = user;
next();
});
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true,
}).then(() => console.log('Connected to MongoDB'));
// Define routes with RBAC middleware
app.get('/dashboard', checkRole('read'), (req, res) => {
res.send('Welcome to the dashboard');
});
app.post('/create-post', checkRole('write'), (req, res) => {
res.send('Post created');
});
app.delete('/delete-post', checkRole('delete'), (req, res) => {
res.send('Post deleted');
});
app.listen(process.env.PORT, () => {
console.log(`Server running at http://localhost:${process.env.PORT}`);
});
Here, we've added a middleware that simulates user authentication by adding the user object to the request. We've also defined three routes (/dashboard
, /create-post
, and /delete-post
) with different permissions, using the checkRole middleware.
Testing Your Implementation
You can now test your RBAC implementation using a tool like Postman or curl. Send requests to the different routes and observe the responses. If the user's role includes the required permission, you should receive a success message; otherwise, you should receive a 403 Forbidden status.
For example, you can test the /dashboard route using curl:
$ curl -X GET http://localhost:3000/dashboard
Conclusion
In this article, we've demonstrated how to implement role-based access control (RBAC) in a Node.js Express application. We've defined roles and permissions, created a middleware function to enforce role-based authorization, and applied it to our application routes. This implementation ensures that users can only access resources and perform actions based on their assigned roles, enhancing the security of your web application.
Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.
Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.
Momo: NGUYỄN ANH TUẤN - 0374226770
TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)
All rights reserved