mirror of
https://github.com/rgrgogu/new_starr.git
synced 2026-09-27 00:12:54 +08:00
chore: relocate backend into apps/api ahead of monorepo merge
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,77 @@
|
||||
/***********************************************************************************************************************************************************************
|
||||
* 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 };
|
||||
Reference in New Issue
Block a user