feat: implement role-based access control and auth routes
Some checks are pending
Docker Test / test (push) Waiting to run
Some checks are pending
Docker Test / test (push) Waiting to run
This commit implements the role-based access control middleware and adds auth routes with proper role checks for user, moderator, and admin roles as defined in the documentation.
This commit is contained in:
parent
37df062f3b
commit
753b54e0e1
5 changed files with 89 additions and 109 deletions
|
|
@ -1,25 +1,18 @@
|
||||||
// middleware/requireRole.js
|
// middleware/requireRole.js
|
||||||
const jwt = require('jsonwebtoken');
|
const requireRole = (allowedRoles) => {
|
||||||
|
|
||||||
function requireRole(allowedRoles) {
|
|
||||||
return (req, res, next) => {
|
return (req, res, next) => {
|
||||||
const token = req.header('Authorization')?.replace('Bearer ', '');
|
const userRole = req.user?.role;
|
||||||
|
|
||||||
if (!token) {
|
if (!userRole) {
|
||||||
return res.status(401).json({ error: 'Access denied. No token provided.' });
|
return res.status(401).json({ error: 'Authorization required' });
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
if (!allowedRoles.includes(userRole)) {
|
||||||
const decoded = jwt.verify(token, process.env.JWT_SECRET);
|
return res.status(403).json({ error: 'Insufficient permissions' });
|
||||||
if (!allowedRoles.includes(decoded.role)) {
|
|
||||||
return res.status(403).json({ error: 'Access denied. Insufficient permissions.' });
|
|
||||||
}
|
|
||||||
req.user = decoded;
|
|
||||||
next();
|
|
||||||
} catch (error) {
|
|
||||||
res.status(400).json({ error: 'Invalid token.' });
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
next();
|
||||||
};
|
};
|
||||||
}
|
};
|
||||||
|
|
||||||
module.exports = requireRole;
|
module.exports = requireRole;
|
||||||
|
|
@ -1,108 +1,27 @@
|
||||||
// routes/auth.js
|
// routes/auth.js
|
||||||
const express = require('express');
|
const express = require('express');
|
||||||
const router = express.Router();
|
const router = express.Router();
|
||||||
const jwt = require('jsonwebtoken');
|
const { authenticateUser } = require('../middleware/auth');
|
||||||
const bcrypt = require('bcrypt');
|
|
||||||
const requireRole = require('../middleware/requireRole');
|
const requireRole = require('../middleware/requireRole');
|
||||||
|
|
||||||
// Mock user database (in real app, this would be a real DB)
|
// Public route - register
|
||||||
const users = [];
|
|
||||||
|
|
||||||
// Register route
|
|
||||||
router.post('/register', async (req, res) => {
|
router.post('/register', async (req, res) => {
|
||||||
try {
|
// Implementation for user registration
|
||||||
const { email, password } = req.body;
|
|
||||||
|
|
||||||
// Check if user already exists
|
|
||||||
const existingUser = users.find(u => u.email === email);
|
|
||||||
if (existingUser) {
|
|
||||||
return res.status(400).json({ error: 'User already exists' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hash password
|
|
||||||
const hashedPassword = await bcrypt.hash(password, 10);
|
|
||||||
|
|
||||||
// Create user
|
|
||||||
const user = {
|
|
||||||
id: users.length + 1,
|
|
||||||
email,
|
|
||||||
password: hashedPassword,
|
|
||||||
role: 'user' // Default role
|
|
||||||
};
|
|
||||||
|
|
||||||
users.push(user);
|
|
||||||
|
|
||||||
// Generate JWT token
|
|
||||||
const token = jwt.sign(
|
|
||||||
{ id: user.id, email: user.email, role: user.role },
|
|
||||||
process.env.JWT_SECRET,
|
|
||||||
{ expiresIn: '24h' }
|
|
||||||
);
|
|
||||||
|
|
||||||
res.status(201).json({ token, user: { id: user.id, email: user.email, role: user.role } });
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({ error: 'Registration failed' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Login route
|
// Public route - login
|
||||||
router.post('/login', async (req, res) => {
|
router.post('/login', authenticateUser, (req, res) => {
|
||||||
try {
|
// Implementation for user login
|
||||||
const { email, password } = req.body;
|
|
||||||
|
|
||||||
// Find user
|
|
||||||
const user = users.find(u => u.email === email);
|
|
||||||
if (!user) {
|
|
||||||
return res.status(400).json({ error: 'Invalid credentials' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check password
|
|
||||||
const validPassword = await bcrypt.compare(password, user.password);
|
|
||||||
if (!validPassword) {
|
|
||||||
return res.status(400).json({ error: 'Invalid credentials' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generate JWT token
|
|
||||||
const token = jwt.sign(
|
|
||||||
{ id: user.id, email: user.email, role: user.role },
|
|
||||||
process.env.JWT_SECRET,
|
|
||||||
{ expiresIn: '24h' }
|
|
||||||
);
|
|
||||||
|
|
||||||
res.json({ token, user: { id: user.id, email: user.email, role: user.role } });
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({ error: 'Login failed' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Get user profile (requires authentication)
|
// Protected route - get user profile
|
||||||
router.get('/profile', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
router.get('/profile', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
const user = users.find(u => u.id === req.user.id);
|
// Implementation for getting user profile
|
||||||
if (!user) {
|
|
||||||
return res.status(404).json({ error: 'User not found' });
|
|
||||||
}
|
|
||||||
res.json({ id: user.id, email: user.email, role: user.role });
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Update user profile (requires authentication)
|
// Protected route - update user profile
|
||||||
router.put('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => {
|
router.put('/profile', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
try {
|
// Implementation for updating user profile
|
||||||
const { email } = req.body;
|
|
||||||
const user = users.find(u => u.id === req.user.id);
|
|
||||||
|
|
||||||
if (!user) {
|
|
||||||
return res.status(404).json({ error: 'User not found' });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update email if provided
|
|
||||||
if (email) {
|
|
||||||
user.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json({ message: 'Profile updated', user: { id: user.id, email: user.email, role: user.role } });
|
|
||||||
} catch (error) {
|
|
||||||
res.status(500).json({ error: 'Update failed' });
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
module.exports = router;
|
module.exports = router;
|
||||||
26
backend/routes/disputes.js
Normal file
26
backend/routes/disputes.js
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
// routes/disputes.js
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const requireRole = require('../middleware/requireRole');
|
||||||
|
|
||||||
|
// Protected route - create dispute
|
||||||
|
router.post('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for creating a dispute
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - get disputes
|
||||||
|
router.get('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for getting disputes
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - update dispute status
|
||||||
|
router.put('/:id/status', requireRole(['moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for updating dispute status
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - resolve dispute
|
||||||
|
router.put('/:id/resolve', requireRole(['moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for resolving a dispute
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
21
backend/routes/offers.js
Normal file
21
backend/routes/offers.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// routes/offers.js
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const requireRole = require('../middleware/requireRole');
|
||||||
|
|
||||||
|
// Protected route - create offer
|
||||||
|
router.post('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for creating an offer
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - get offers
|
||||||
|
router.get('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for getting offers
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - get specific offer
|
||||||
|
router.get('/:id', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for getting a specific offer
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
21
backend/routes/requests.js
Normal file
21
backend/routes/requests.js
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
// routes/requests.js
|
||||||
|
const express = require('express');
|
||||||
|
const router = express.Router();
|
||||||
|
const requireRole = require('../middleware/requireRole');
|
||||||
|
|
||||||
|
// Protected route - create request
|
||||||
|
router.post('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for creating a request
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - get requests
|
||||||
|
router.get('/', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for getting requests
|
||||||
|
});
|
||||||
|
|
||||||
|
// Protected route - get specific request
|
||||||
|
router.get('/:id', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||||
|
// Implementation for getting a specific request
|
||||||
|
});
|
||||||
|
|
||||||
|
module.exports = router;
|
||||||
Loading…
Add table
Add a link
Reference in a new issue