mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
77 lines
3.2 KiB
JavaScript
77 lines
3.2 KiB
JavaScript
/***********************************************************************************************************************************************************************
|
|
* File Name: rbac.middleware.js
|
|
* Type of Program: Middleware
|
|
* Description: Role-Based Access Control (RBAC) guards.
|
|
* Hierarchy: admin > staff > user (client)
|
|
*
|
|
* Exported guards:
|
|
* - requireClient() → acc_type in ['user', 'staff', 'admin']
|
|
* - requireStaff() → acc_type in ['staff', 'admin']
|
|
* - requireAdmin() → acc_type === 'admin' only
|
|
* - requireOwnerOrStaff() → owns the resource OR is staff/admin
|
|
* - requireOwnerOrAdmin() → owns the resource OR is admin
|
|
*
|
|
* Author: rgrgogu
|
|
* Date Created: Oct. 6, 2025
|
|
***********************************************************************************************************************************************************************
|
|
* HOW TO USE:
|
|
* const { requireAdmin, requireStaff } = require('../middleware/rbac.middleware');
|
|
* // Must be used AFTER authenticate middleware
|
|
* router.get('/users', authenticate, requireStaff(), handler);
|
|
* router.delete('/users/:id', authenticate, requireAdmin(), handler);
|
|
***********************************************************************************************************************************************************************/
|
|
const R = require('../utils/response.util');
|
|
|
|
const ROLES = { user: 1, staff: 2, admin: 3 };
|
|
|
|
/**
|
|
* Generic role guard factory.
|
|
* @param {string[]} allowed - list of acc_type values that can pass
|
|
*/
|
|
const requireRole = (allowed) => (req, res, next) => {
|
|
if (!req.user)
|
|
return R.error(res, 'Authentication required.', 401);
|
|
|
|
if (!allowed.includes(req.user.acc_type))
|
|
return R.error(res, 'You do not have permission to access this resource.', 403);
|
|
|
|
next();
|
|
};
|
|
|
|
/** Any logged-in user (client, staff, admin) */
|
|
const requireClient = () => requireRole(['user', 'staff', 'admin']);
|
|
|
|
/** Staff or Admin */
|
|
const requireStaff = () => requireRole(['staff', 'admin']);
|
|
|
|
/** Admin only */
|
|
const requireAdmin = () => requireRole(['admin']);
|
|
|
|
/**
|
|
* Allows resource owner OR staff/admin.
|
|
* Reads the owner's user_id from req.params.user_id or req.params.id.
|
|
*/
|
|
const requireOwnerOrStaff = () => (req, res, next) => {
|
|
if (!req.user) return R.error(res, 'Authentication required.', 401);
|
|
const targetId = Number(req.params.user_id || req.params.id);
|
|
const isOwner = req.user.user_id === targetId;
|
|
const elevated = ['staff', 'admin'].includes(req.user.acc_type);
|
|
if (!isOwner && !elevated)
|
|
return R.error(res, 'You do not have permission.', 403);
|
|
next();
|
|
};
|
|
|
|
/**
|
|
* Allows resource owner OR admin only.
|
|
*/
|
|
const requireOwnerOrAdmin = () => (req, res, next) => {
|
|
if (!req.user) return R.error(res, 'Authentication required.', 401);
|
|
const targetId = Number(req.params.user_id || req.params.id);
|
|
const isOwner = req.user.user_id === targetId;
|
|
const isAdmin = req.user.acc_type === 'admin';
|
|
if (!isOwner && !isAdmin)
|
|
return R.error(res, 'You do not have permission.', 403);
|
|
next();
|
|
};
|
|
|
|
module.exports = { requireClient, requireStaff, requireAdmin, requireOwnerOrStaff, requireOwnerOrAdmin }; |