Post

Episode 11 – Admin Dashboard with Role-Based Access Control (RBAC)

- Implement an Admin-only dashboard for managing products, users, and orders
- Create a role field in the User model (admin, user)
- Add middleware to restrict access based on roles
- Build protected admin routes and a basic dashboard UI

Episode 11 – Admin Dashboard with Role-Based Access Control (RBAC)

1. Extend the User Model with Role

Update models/User.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
const mongoose = require('mongoose');

const userSchema = new mongoose.Schema({
  email: String,
  password: String,
  role: {
    type: String,
    enum: ['user', 'admin'],
    default: 'user'
  }
});

module.exports = mongoose.model('User', userSchema);

2. Assign Role During Registration or in MongoDB

Option 1: Assign manually after registering:

1
2
# In MongoDB shell or Compass
db.users.updateOne({ email: "admin@example.com" }, { $set: { role: "admin" } })

Option 2: Modify registration logic:

1
2
3
4
5
6
// Example: default role or conditionally set to admin
const user = new User({
  email,
  password: hashedPassword,
  role: email === 'admin@example.com' ? 'admin' : 'user'
});

3. Create Middleware to Check Roles

In middlewares/roleCheck.js:

1
2
3
4
5
6
7
module.exports = function requireRole(role) {
  return function (req, res, next) {
    if (!req.user) return res.status(401).send("Not logged in");
    if (req.user.role !== role) return res.status(403).send("Forbidden");
    next();
  };
};

Also ensure your authMiddleware sets req.user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
const jwt = require('jsonwebtoken');
const User = require('../models/User');

async function authMiddleware(req, res, next) {
  const token = req.cookies.token;
  if (!token) return res.status(401).send('No token');

  try {
    const decoded = jwt.verify(token, process.env.JWT_SECRET);
    const user = await User.findById(decoded.id);
    req.user = user;
    next();
  } catch (err) {
    res.status(403).send('Invalid token');
  }
}

4. Protect Admin Routes

In your route file:

1
2
3
4
5
6
7
8
9
10
11
const express = require('express');
const router = express.Router();
const authMiddleware = require('../middlewares/auth');
const requireRole = require('../middlewares/roleCheck');

// Protect admin panel
router.get('/admin', authMiddleware, requireRole('admin'), (req, res) => {
  res.render('admin-dashboard', { user: req.user });
});

module.exports = router;

5. Admin Dashboard View (Handlebars Example)

views/admin-dashboard.handlebars:

1
2
3
4
5
6
7
8
<h1>Admin Dashboard</h1>
<p>Welcome, </p>

<ul>
  <li><a href="/admin/products">Manage Products</a></li>
  <li><a href="/admin/orders">View Orders</a></li>
  <li><a href="/admin/users">Manage Users</a></li>
</ul>

For React: You’d fetch from protected API endpoints like /api/admin/products, using the same authMiddleware + requireRole.

In Handlebars layout:

1
2
3
4
5
  
    <a href="/admin">Admin Dashboard</a>
  

Create custom Handlebars helper ifEquals:

1
2
3
hbs.registerHelper('ifEquals', function (arg1, arg2, options) {
  return (arg1 === arg2) ? options.fn(this) : options.inverse(this);
});
This post is licensed under CC BY 4.0 by the author.