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 is contained in:
parent
91eb0828e3
commit
7c9862a08a
3 changed files with 344 additions and 45 deletions
|
|
@ -1,27 +1,309 @@
|
|||
// routes/auth.js
|
||||
const express = require('express');
|
||||
const router = express.Router();
|
||||
const { authenticateUser } = require('../middleware/auth');
|
||||
const bcrypt = require('bcrypt');
|
||||
const jwt = require('jsonwebtoken');
|
||||
const db = require('../db');
|
||||
const requireRole = require('../middleware/requireRole');
|
||||
|
||||
// Public route - register
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/register:
|
||||
* post:
|
||||
* summary: Registriert einen neuen Benutzer
|
||||
* tags: [Auth]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - username
|
||||
* - email
|
||||
* - password
|
||||
* properties:
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* password:
|
||||
* type: string
|
||||
* responses:
|
||||
* 201:
|
||||
* description: Benutzer erfolgreich registriert
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* user:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* role:
|
||||
* type: string
|
||||
* token:
|
||||
* type: string
|
||||
* 400:
|
||||
* description: Ungültige Eingabedaten
|
||||
* 409:
|
||||
* description: Benutzer existiert bereits
|
||||
*/
|
||||
router.post('/register', async (req, res) => {
|
||||
// Implementation for user registration
|
||||
const { username, email, password } = req.body;
|
||||
|
||||
if (!username || !email || !password) {
|
||||
return res.status(400).json({ error: 'Missing required fields' });
|
||||
}
|
||||
|
||||
try {
|
||||
// Prüfen, ob Benutzer bereits existiert
|
||||
const existingUser = await db.get('SELECT id FROM users WHERE email = ?', [email]);
|
||||
if (existingUser) {
|
||||
return res.status(409).json({ error: 'User already exists' });
|
||||
}
|
||||
|
||||
// Passwort hashen
|
||||
const hashedPassword = await bcrypt.hash(password, 10);
|
||||
|
||||
// Neuen Benutzer anlegen
|
||||
const result = await db.run(
|
||||
'INSERT INTO users (username, email, password_hash, role) VALUES (?, ?, ?, ?)',
|
||||
[username, email, hashedPassword, 'user']
|
||||
);
|
||||
|
||||
// Token generieren
|
||||
const token = jwt.sign(
|
||||
{ id: result.lastID, username, email, role: 'user' },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
|
||||
res.status(201).json({
|
||||
user: {
|
||||
id: result.lastID,
|
||||
username,
|
||||
email,
|
||||
role: 'user'
|
||||
},
|
||||
token
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Public route - login
|
||||
router.post('/login', authenticateUser, (req, res) => {
|
||||
// Implementation for user login
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/login:
|
||||
* post:
|
||||
* summary: Loggt einen Benutzer ein
|
||||
* tags: [Auth]
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* required:
|
||||
* - email
|
||||
* - password
|
||||
* properties:
|
||||
* email:
|
||||
* type: string
|
||||
* password:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Login erfolgreich
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* user:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* role:
|
||||
* type: string
|
||||
* token:
|
||||
* type: string
|
||||
* 400:
|
||||
* description: Ungültige Eingabedaten
|
||||
* 401:
|
||||
* description: Falsche Anmeldedaten
|
||||
*/
|
||||
router.post('/login', async (req, res) => {
|
||||
const { email, password } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({ error: 'Missing email or password' });
|
||||
}
|
||||
|
||||
try {
|
||||
const user = await db.get('SELECT id, username, email, password_hash, role FROM users WHERE email = ?', [email]);
|
||||
if (!user) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
const isValidPassword = await bcrypt.compare(password, user.password_hash);
|
||||
if (!isValidPassword) {
|
||||
return res.status(401).json({ error: 'Invalid credentials' });
|
||||
}
|
||||
|
||||
// Token generieren
|
||||
const token = jwt.sign(
|
||||
{ id: user.id, username: user.username, email: user.email, role: user.role },
|
||||
process.env.JWT_SECRET,
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
|
||||
res.json({
|
||||
user: {
|
||||
id: user.id,
|
||||
username: user.username,
|
||||
email: user.email,
|
||||
role: user.role
|
||||
},
|
||||
token
|
||||
});
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Protected route - get user profile
|
||||
router.get('/profile', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||
// Implementation for getting user profile
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/profile:
|
||||
* get:
|
||||
* summary: Holt das Profil des eingeloggten Benutzers
|
||||
* tags: [Auth]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Profil erfolgreich abgerufen
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* user:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* role:
|
||||
* type: string
|
||||
* 401:
|
||||
* description: Nicht autorisiert
|
||||
*/
|
||||
router.get('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => {
|
||||
try {
|
||||
const user = await db.get('SELECT id, username, email, role FROM users WHERE id = ?', [req.user.id]);
|
||||
if (!user) {
|
||||
return res.status(404).json({ error: 'User not found' });
|
||||
}
|
||||
res.json({ user });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
// Protected route - update user profile
|
||||
router.put('/profile', requireRole(['user', 'moderator', 'admin']), (req, res) => {
|
||||
// Implementation for updating user profile
|
||||
/**
|
||||
* @swagger
|
||||
* /auth/profile:
|
||||
* put:
|
||||
* summary: Aktualisiert das Profil des eingeloggten Benutzers
|
||||
* tags: [Auth]
|
||||
* security:
|
||||
* - bearerAuth: []
|
||||
* requestBody:
|
||||
* required: true
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* responses:
|
||||
* 200:
|
||||
* description: Profil erfolgreich aktualisiert
|
||||
* content:
|
||||
* application/json:
|
||||
* schema:
|
||||
* type: object
|
||||
* properties:
|
||||
* user:
|
||||
* type: object
|
||||
* properties:
|
||||
* id:
|
||||
* type: integer
|
||||
* username:
|
||||
* type: string
|
||||
* email:
|
||||
* type: string
|
||||
* role:
|
||||
* type: string
|
||||
* 400:
|
||||
* description: Ungültige Eingabedaten
|
||||
* 401:
|
||||
* description: Nicht autorisiert
|
||||
*/
|
||||
router.put('/profile', requireRole(['user', 'moderator', 'admin']), async (req, res) => {
|
||||
const { username, email } = req.body;
|
||||
|
||||
if (!username && !email) {
|
||||
return res.status(400).json({ error: 'At least one field must be provided' });
|
||||
}
|
||||
|
||||
try {
|
||||
let updateFields = [];
|
||||
let values = [];
|
||||
|
||||
if (username) {
|
||||
updateFields.push('username = ?');
|
||||
values.push(username);
|
||||
}
|
||||
if (email) {
|
||||
updateFields.push('email = ?');
|
||||
values.push(email);
|
||||
}
|
||||
|
||||
values.push(req.user.id);
|
||||
|
||||
const query = `UPDATE users SET ${updateFields.join(', ')} WHERE id = ?`;
|
||||
await db.run(query, values);
|
||||
|
||||
// Aktualisierte Daten abrufen
|
||||
const updatedUser = await db.get('SELECT id, username, email, role FROM users WHERE id = ?', [req.user.id]);
|
||||
res.json({ user: updatedUser });
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
res.status(500).json({ error: 'Internal server error' });
|
||||
}
|
||||
});
|
||||
|
||||
module.exports = router;
|
||||
Loading…
Add table
Add a link
Reference in a new issue