harmadik gyakorlat

This commit is contained in:
magdo
2026-02-25 20:16:03 +01:00
parent a837f5ecba
commit ffca701b84
34 changed files with 3397 additions and 0 deletions
@@ -0,0 +1,160 @@
/**
* AuthController
*
* FELADAT: Implementáld az alábbi metódusokat!
*
* Ez a controller felelős az authentication és authorization kezeléséért.
* A következő funkciók implementálása szükséges:
*
* 1. register() - Felhasználó regisztráció
* - Email és username uniqueness ellenőrzés
* - Jelszó hash-elés bcrypt-tel
* - User létrehozása a repository-n keresztül
* - JWT token generálás
* - Cookie beállítás
*
* 2. login() - Bejelentkezés
* - User keresése email vagy username alapján
* - Jelszó ellenőrzés bcrypt.compare()-val
* - JWT token generálás (access és refresh token)
* - Cookie-k beállítása
* - Redis-ben session tárolás (opcionális)
*
* 3. logout() - Kijelentkezés
* - Cookie-k törlése
* - Redis session törlése
*
* 4. refreshToken() - Token frissítés
* - Refresh token validálás
* - Új access token generálás
*
* 5. getCurrentUser() - Bejelentkezett user adatai
* - req.user alapján user visszaadása
*/
export class AuthController {
constructor(userRepository) {
this.userRepository = userRepository;
}
/**
* POST /api/auth/register
* Új felhasználó regisztrációja
*/
async register(req, res) {
try {
// TODO: Implementáld a regisztrációt
// 1. Validáld az input adatokat (email, username, password)
// 2. Ellenőrizd, hogy létezik-e már a user (email vagy username)
// 3. Hash-eld a jelszót bcrypt-tel
// 4. Hozd létre a user-t a repository-n keresztül
// 5. Generálj JWT tokent
// 6. Állítsd be a cookie-kat
// 7. Küldd vissza a user adatokat (jelszó nélkül!)
res.status(501).json({
success: false,
error: 'Register not implemented yet - this is your task!'
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* POST /api/auth/login
* Bejelentkezés
*/
async login(req, res) {
try {
// TODO: Implementáld a login-t
// 1. Keresd meg a user-t email vagy username alapján
// 2. Ellenőrizd a jelszót bcrypt.compare()-val
// 3. Generálj JWT access és refresh tokent
// 4. Állítsd be a cookie-kat (httpOnly, secure)
// 5. Opcionálisan tárolj session-t Redis-ben
// 6. Küldd vissza a user adatokat és tokeneket
res.status(501).json({
success: false,
error: 'Login not implemented yet - this is your task!'
});
} catch (error) {
res.status(401).json({
success: false,
error: error.message
});
}
}
/**
* POST /api/auth/logout
* Kijelentkezés
*/
async logout(req, res) {
try {
// TODO: Implementáld a logout-ot
// 1. Töröld a cookie-kat
// 2. Töröld a Redis session-t (ha van)
// 3. Invalidáld a refresh tokent
res.status(501).json({
success: false,
error: 'Logout not implemented yet - this is your task!'
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* POST /api/auth/refresh
* Access token frissítése refresh token alapján
*/
async refreshToken(req, res) {
try {
// TODO: Implementáld a token refresh-t
// 1. Olvasd ki a refresh tokent a cookie-ból
// 2. Validáld a refresh tokent
// 3. Generálj új access tokent
// 4. Állítsd be az új cookie-t
res.status(501).json({
success: false,
error: 'Refresh token not implemented yet - this is your task!'
});
} catch (error) {
res.status(401).json({
success: false,
error: error.message
});
}
}
/**
* GET /api/auth/me
* Bejelentkezett felhasználó adatai
*/
async getCurrentUser(req, res) {
try {
// TODO: Implementáld a current user lekérést
// 1. Olvasd ki a user-t req.user-ből (amit az auth middleware állít be)
// 2. Küldd vissza a user publikus adatait
res.status(501).json({
success: false,
error: 'Get current user not implemented yet - this is your task!'
});
} catch (error) {
res.status(401).json({
success: false,
error: error.message
});
}
}
}
@@ -0,0 +1,179 @@
import { CreateBlogCommand } from '../../application/commands/CreateBlogCommand.js';
import { UpdateBlogCommand } from '../../application/commands/UpdateBlogCommand.js';
import { DeleteBlogCommand } from '../../application/commands/DeleteBlogCommand.js';
import { GetBlogQuery, GetAllBlogsQuery, GetUserBlogsQuery } from '../../application/queries/BlogQueries.js';
/**
* BlogController
* Blog műveletek kezelése
*/
export class BlogController {
constructor(createHandler, updateHandler, deleteHandler, queryHandler) {
this.createHandler = createHandler;
this.updateHandler = updateHandler;
this.deleteHandler = deleteHandler;
this.queryHandler = queryHandler;
}
/**
* Blog létrehozása
* POST /api/blogs
*/
async createBlog(req, res) {
try {
// FIGYELEM: req.user-t az auth middleware-nek kell beállítania
// Ez a feladat része - implementálandó!
const authorId = req.user?.id;
if (!authorId) {
return res.status(401).json({ error: 'Authentication required' });
}
const command = new CreateBlogCommand({
...req.body,
authorId
});
const blog = await this.createHandler.handle(command);
res.status(201).json({
success: true,
data: blog.toObject()
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* Blog módosítása
* PUT /api/blogs/:id
*/
async updateBlog(req, res) {
try {
const userId = req.user?.id;
if (!userId) {
return res.status(401).json({ error: 'Authentication required' });
}
const command = new UpdateBlogCommand(req.params.id, req.body);
// FIGYELEM: Authorization ellenőrzés szükséges!
// Csak a szerző vagy admin módosíthatja
// Ez a feladat része - implementálandó!
const blog = await this.updateHandler.handle(command);
res.json({
success: true,
data: blog.toObject()
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* Blog törlése
* DELETE /api/blogs/:id
*/
async deleteBlog(req, res) {
try {
const userId = req.user?.id;
if (!userId) {
return res.status(401).json({ error: 'Authentication required' });
}
const command = new DeleteBlogCommand(req.params.id, userId);
const result = await this.deleteHandler.handle(command);
res.json({
success: true,
message: result.message
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* Egy blog lekérése
* GET /api/blogs/:id
*/
async getBlog(req, res) {
try {
const query = new GetBlogQuery(req.params.id);
const blog = await this.queryHandler.handleGetBlog(query);
res.json({
success: true,
data: blog.toObject()
});
} catch (error) {
res.status(404).json({
success: false,
error: error.message
});
}
}
/**
* Összes blog lekérése
* GET /api/blogs
*/
async getAllBlogs(req, res) {
try {
const query = new GetAllBlogsQuery({
publishedOnly: req.query.published === 'true',
limit: req.query.limit ? parseInt(req.query.limit) : undefined,
offset: req.query.offset ? parseInt(req.query.offset) : 0
});
const blogs = await this.queryHandler.handleGetAllBlogs(query);
res.json({
success: true,
data: blogs.map(blog => blog.toObject()),
count: blogs.length
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
/**
* User blogjai
* GET /api/users/:userId/blogs
*/
async getUserBlogs(req, res) {
try {
const query = new GetUserBlogsQuery(req.params.userId);
const blogs = await this.queryHandler.handleGetUserBlogs(query);
res.json({
success: true,
data: blogs.map(blog => blog.toObject()),
count: blogs.length
});
} catch (error) {
res.status(400).json({
success: false,
error: error.message
});
}
}
}
@@ -0,0 +1,112 @@
/**
* Authentication Middleware
*
* FELADAT: Implementáld az authentication middleware-t!
*
* Ez a middleware felelős azért, hogy:
* 1. Ellenőrizze a JWT tokent (cookie-ból vagy Authorization header-ből)
* 2. Validálja a tokent
* 3. Beállítsa a req.user objektumot a dekódolt token alapján
* 4. Hiba esetén 401 Unauthorized választ küldjön
*
* Példa használat:
* router.get('/protected', authenticateToken, (req, res) => {
* res.json({ user: req.user });
* });
*/
export function authenticateToken(req, res, next) {
try {
// TODO: Implementáld az authentication-t
// 1. Olvasd ki a tokent a cookie-ból vagy Authorization header-ből
// 2. Validáld a tokent jwt.verify()-val
// 3. Állítsd be req.user-t a dekódolt token payload-jából
// 4. Hívd meg a next()-et, hogy tovább menjen a request
// Ideiglenes: mindig hiba, amíg nincs implementálva
return res.status(401).json({
success: false,
error: 'Authentication middleware not implemented yet - this is your task!'
});
} catch (error) {
return res.status(401).json({
success: false,
error: 'Invalid or expired token'
});
}
}
/**
* Authorization Middleware - Role Check
*
* FELADAT: Implementáld a role-based authorization middleware-t!
*
* Ez a middleware ellenőrzi, hogy a bejelentkezett usernek van-e megfelelő role-ja.
*
* Példa használat:
* router.delete('/admin/users/:id', authenticateToken, requireRole(['ADMIN']), (req, res) => {
* // Csak ADMIN role-lal lehet törölni
* });
*/
export function requireRole(allowedRoles) {
return (req, res, next) => {
try {
// TODO: Implementáld a role check-et
// 1. Ellenőrizd, hogy req.user létezik-e (authenticateToken után fut)
// 2. Ellenőrizd, hogy req.user.role benne van-e az allowedRoles tömbben
// 3. Ha nincs jogosultság, küldj 403 Forbidden választ
// 4. Ha van jogosultság, hívd meg a next()-et
return res.status(403).json({
success: false,
error: 'Authorization middleware not implemented yet - this is your task!'
});
} catch (error) {
return res.status(403).json({
success: false,
error: 'Insufficient permissions'
});
}
};
}
/**
* Resource Owner Check
*
* FELADAT: Implementáld a resource ownership ellenőrzést!
*
* Ez a middleware ellenőrzi, hogy a user tulajdonosa-e az adott resource-nak.
* Például: csak a blog szerzője módosíthatja/törölheti a blogot.
*
* @param {Function} getResourceOwnerId - Függvény, ami visszaadja a resource owner ID-t
*
* Példa használat:
* router.put('/blogs/:id',
* authenticateToken,
* checkOwnership(async (req) => {
* const blog = await blogRepository.findById(req.params.id);
* return blog.authorId;
* }),
* (req, res) => { ... }
* );
*/
export function checkOwnership(getResourceOwnerId) {
return async (req, res, next) => {
try {
// TODO: Implementáld az ownership check-et
// 1. Szerezd meg a resource owner ID-t a getResourceOwnerId függvénnyel
// 2. Ellenőrizd, hogy req.user.id === ownerId VAGY req.user.role === 'ADMIN'
// 3. Ha nem egyezik és nem admin, küldj 403 Forbidden választ
// 4. Ha OK, hívd meg a next()-et
return res.status(403).json({
success: false,
error: 'Ownership check middleware not implemented yet - this is your task!'
});
} catch (error) {
return res.status(403).json({
success: false,
error: 'Access denied'
});
}
};
}
@@ -0,0 +1,26 @@
/**
* Error Handler Middleware
* Globális error handling
*/
export function errorHandler(err, req, res, next) {
console.error('Error:', err);
const statusCode = err.statusCode || 500;
const message = err.message || 'Internal Server Error';
res.status(statusCode).json({
success: false,
error: message,
...(process.env.NODE_ENV === 'development' && { stack: err.stack })
});
}
/**
* Not Found Handler
*/
export function notFoundHandler(req, res) {
res.status(404).json({
success: false,
error: 'Route not found'
});
}
@@ -0,0 +1,21 @@
import express from 'express';
/**
* Auth Routes
*
* FELADAT: Implementáld az auth middleware-t és védett route-okat!
*/
export function createAuthRoutes(authController) {
const router = express.Router();
// Publikus route-ok
router.post('/register', (req, res) => authController.register(req, res));
router.post('/login', (req, res) => authController.login(req, res));
router.post('/refresh', (req, res) => authController.refreshToken(req, res));
// Védett route-ok - FELADAT: add hozzá az auth middleware-t!
router.post('/logout', (req, res) => authController.logout(req, res));
router.get('/me', (req, res) => authController.getCurrentUser(req, res));
return router;
}
@@ -0,0 +1,20 @@
import express from 'express';
/**
* Blog Routes
*/
export function createBlogRoutes(blogController) {
const router = express.Router();
// Publikus route-ok
router.get('/', (req, res) => blogController.getAllBlogs(req, res));
router.get('/:id', (req, res) => blogController.getBlog(req, res));
// Védett route-ok - FELADAT: add hozzá az auth middleware-t!
// Példa: router.post('/', authMiddleware, (req, res) => ...)
router.post('/', (req, res) => blogController.createBlog(req, res));
router.put('/:id', (req, res) => blogController.updateBlog(req, res));
router.delete('/:id', (req, res) => blogController.deleteBlog(req, res));
return router;
}
@@ -0,0 +1,13 @@
import express from 'express';
/**
* User Routes
*/
export function createUserRoutes(blogController) {
const router = express.Router();
// User blogjai
router.get('/:userId/blogs', (req, res) => blogController.getUserBlogs(req, res));
return router;
}