This commit is contained in:
magdo
2026-02-24 01:29:59 +01:00
parent 77f7eb2664
commit 31d4479c63
16 changed files with 4494 additions and 0 deletions
+555
View File
@@ -0,0 +1,555 @@
\section{Middleware}
\begin{frame}{Mi az a middleware?}
\begin{block}{Definíció}
Függvény, amely HTTP kérés és válasz között fut, hozzáfér \texttt{req}, \texttt{res}, \texttt{next}-hez.
\end{block}
\begin{itemize}
\item Láncolható függvények
\item Kérés előfeldolgozás
\item Válasz utófeldolgozás
\item Kérés megszakítás
\end{itemize}
\begin{exampleblock}{Express middleware}
\texttt{function middleware(req, res, next) \{ ... \}}
\end{exampleblock}
\end{frame}
\begin{frame}[shrink=5]{Middleware működése}
\begin{center}
\begin{tikzpicture}[node distance=1.5cm, auto]
\node (browser) [rectangle, draw, text width=2cm, text centered] {Browser};
\node (mw1) [rectangle, draw, right of=browser, xshift=1.5cm, text width=2.5cm, text centered] {Middleware 1\\(Logger)};
\node (mw2) [rectangle, draw, right of=mw1, xshift=2cm, text width=2.5cm, text centered] {Middleware 2\\(Auth)};
\node (route) [rectangle, draw, right of=mw2, xshift=2cm, text width=2cm, text centered] {Route Handler};
\draw[->, thick] (browser) -- node[above] {Request} (mw1);
\draw[->, thick] (mw1) -- node[above] {\texttt{next()}} (mw2);
\draw[->, thick] (mw2) -- node[above] {\texttt{next()}} (route);
\draw[->, thick, dashed] (route) -- node[below] {Response} (browser);
\end{tikzpicture}
\end{center}
\begin{alertblock}{Fontos!}
Ha nem hívod meg a \texttt{next()}-et, a kérés megáll és nem jut el a következő middleware-hez vagy route handler-hez!
\end{alertblock}
\end{frame}
\begin{frame}[shrink=5]{Middleware típusok}
\begin{enumerate}
\item \textbf{Application-level}
\begin{itemize}
\item Egész app-ra
\end{itemize}
\item \textbf{Router-level}
\begin{itemize}
\item Adott routerre
\end{itemize}
\item \textbf{Error-handling}
\begin{itemize}
\item 4 param: \texttt{(err, req, res, next)}
\end{itemize}
\item \textbf{Built-in}
\begin{itemize}
\item \texttt{express.json()}
\end{itemize}
\item \textbf{Third-party}
\begin{itemize}
\item \texttt{cors}, \texttt{helmet}
\end{itemize}
\end{enumerate}
\end{frame}
\begin{frame}[fragile,shrink=10]{Egyszerű logger middleware}
\begin{block}{Request logging - 1. rész}
\small
\begin{verbatim}
const express = require('express');
const app = express();
const logger = (req, res, next) => {
const timestamp = new Date().toISOString();
console.log(`[${timestamp}] ${req.method} ${req.url}`);
next();
};
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile,shrink=10]{Egyszerű logger middleware (folyt.)}
\begin{block}{Request logging - 2. rész (használat)}
\small
\begin{verbatim}
app.use(logger);
app.get('/', (req, res) => {
res.json({ message: 'Hello World' });
});
app.get('/users', (req, res) => {
res.json({ users: ['Alice', 'Bob'] });
});
app.listen(3000);
// Kimenet:
// [2026-02-23T10:30:15.000Z] GET /
// [2026-02-23T10:30:20.000Z] GET /users
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile,shrink=10]{Request timing middleware}
\begin{block}{Válaszidő mérése}
\small
\begin{verbatim}
const requestTimer = (req, res, next) => {
req.startTime = Date.now();
res.on('finish', () => {
const duration = Date.now() - req.startTime;
console.log(`${req.method} ${req.url} - ${duration}ms`);
});
next();
};
app.use(requestTimer);
// Kimenet:
// GET /api/users - 145ms
// POST /api/login - 523ms
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Validation middleware}
\begin{block}{Input validáció - 1. rész}
\small
\begin{verbatim}
// email validáló middleware
const validateEmail = (req, res, next) => {
const { email } = req.body;
if (!email) {
return res.status(400).json({
error: 'Email is required'
});
}
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
if (!emailRegex.test(email)) {
return res.status(400).json({
error: 'Invalid email format'
});
}
next(); // Validáció sikeres, tovább
};
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Validation middleware (folyt.)}
\begin{block}{Input validáció - 2. rész (használat)}
\small
\begin{verbatim}
app.use(express.json()); // Body parser middleware
// Route-specific middleware
app.post('/register', validateEmail, (req, res) => {
const { email, password } = req.body;
// Email már validálva van a middleware által
// Regisztráció logika...
res.json({ message: 'User registered', email });
});
// Több middleware egyszerre
app.post('/login',
validateEmail,
validatePassword, // Másik validator
(req, res) => {
// Login logika...
}
);
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Authentikációs middleware - JWT}
\begin{block}{Token validáció - 1. rész}
\small
\begin{verbatim}
const jwt = require('jsonwebtoken');
const authenticateJWT = (req, res, next) => {
// Token a Authorization header-ből
const authHeader = req.headers.authorization;
if (!authHeader) {
return res.status(401).json({
error: 'Access token required'
});
}
// Bearer TOKEN formátum
const token = authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({
error: 'Token not found'
});
}
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Authentikációs middleware - JWT (folyt.)}
\begin{block}{Token validáció - 2. rész}
\small
\begin{verbatim}
// Token verify
try {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
// Felhasználói adat hozzáadása a request objektumhoz
req.user = decoded; // { userId, email, role, ... }
next(); // Sikeres authentikáció
} catch (error) {
return res.status(403).json({
error: 'Invalid or expired token'
});
}
};
// Használat
app.get('/api/profile', authenticateJWT, (req, res) => {
// req.user elérhető itt
res.json({ user: req.user });
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Autorizációs middleware - Role-based}
\begin{block}{Szerepkör ellenőrzés}
\small
\begin{verbatim}
// Role-based access control middleware factory
const requireRole = (role) => {
return (req, res, next) => {
// Feltételezzük, hogy az authenticateJWT már futott
if (!req.user) {
return res.status(401).json({
error: 'Not authenticated'
});
}
if (req.user.role !== role) {
return res.status(403).json({
error: `Forbidden: ${role} role required`
});
}
next(); // Jogosultság OK
};
};
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Autorizációs middleware (folyt.)}
\begin{block}{Használat szerepkör ellenőrzésre}
\small
\begin{verbatim}
// Admin-only endpoint
app.delete('/api/users/:id',
authenticateJWT, // 1. Authentikáció
requireRole('admin'), // 2. Autorizáció
(req, res) => {
// Csak admin férhet ide
const userId = req.params.id;
// Delete user logika...
res.json({ message: 'User deleted' });
}
);
// Több szerepkör támogatása
const requireAnyRole = (...roles) => {
return (req, res, next) => {
if (!req.user || !roles.includes(req.user.role)) {
return res.status(403).json({ error: 'Forbidden' });
}
next();
};
};
app.get('/api/reports', authenticateJWT, requireAnyRole('admin', 'manager'), ...);
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Rate limiting middleware}
\begin{block}{API hívások korlátozása}
\small
\begin{verbatim}
const rateLimit = require('express-rate-limit');
// Rate limiter konfiguráció
const limiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 perc
max: 100, // Max 100 kérés 15 percenként
message: 'Too many requests, please try again later',
standardHeaders: true, // RateLimit-* headers
legacyHeaders: false
});
// Application-level
app.use('/api/', limiter);
// Strict limiter login-hoz
const loginLimiter = rateLimit({
windowMs: 15 * 60 * 1000,
max: 5, // Max 5 login kísérlet 15 percenként
skipSuccessfulRequests: true // Sikeres login nem számít bele
});
app.post('/api/login', loginLimiter, (req, res) => { ... });
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Error handling middleware}
\begin{block}{Központi hibakezelés}
\small
\begin{verbatim}
// Error handling middleware (4 paraméter!)
const errorHandler = (err, req, res, next) => {
// Logolás
console.error('Error:', err);
// Custom error osztályok kezelése
if (err.statusCode) {
return res.status(err.statusCode).json({
error: err.name,
message: err.message
});
}
// Váratlan hibák
res.status(500).json({
error: 'InternalServerError',
message: 'Something went wrong'
});
};
// Error handler middleware UTOLJÁRA kell regisztrálni!
app.use(errorHandler);
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Error handling használata}
\begin{block}{Hibák továbbítása a next()-el}
\small
\begin{verbatim}
// Async route handler
app.get('/api/users/:id', async (req, res, next) => {
try {
const user = await User.findById(req.params.id);
if (!user) {
const error = new Error('User not found');
error.statusCode = 404;
throw error; // vagy: return next(error);
}
res.json({ user });
} catch (error) {
next(error); // Error handler middleware-nek továbbítja
}
});
// A errorHandler middleware automatikusan feldolgozza
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{CORS middleware}
\begin{block}{Cross-Origin Resource Sharing}
\small
\begin{verbatim}
const cors = require('cors');
// Egyszerű CORS - minden origin engedélyezve
app.use(cors());
// Konfigurált CORS
const corsOptions = {
origin: 'https://frontend.example.com', // Engedélyezett origin
methods: ['GET', 'POST', 'PUT', 'DELETE'],
allowedHeaders: ['Content-Type', 'Authorization'],
credentials: true, // Cookie-k engedélyezése
maxAge: 86400 // Preflight cache 24 óra
};
app.use(cors(corsOptions));
// Route-specific CORS
app.get('/api/public', cors(), (req, res) => {
res.json({ message: 'Public data' });
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Security middleware - Helmet}
\begin{block}{HTTP header biztonság}
\small
\begin{verbatim}
const helmet = require('helmet');
// Helmet middleware - biztonságos HTTP headerek
app.use(helmet());
// Helmet beállítja:
// - Content-Security-Policy
// - X-DNS-Prefetch-Control
// - X-Frame-Options (SAMEORIGIN)
// - X-Content-Type-Options (nosniff)
// - X-XSS-Protection
// stb.
// Egyedi konfiguráció
app.use(helmet({
contentSecurityPolicy: {
directives: {
defaultSrc: ["'self'"],
styleSrc: ["'self'", "'unsafe-inline'"]
}
}
}));
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}[fragile]{Middleware láncolás}
\begin{block}{Több middleware egyidejű használata}
\small
\begin{verbatim}
// Middleware láncolás egy route-on
app.post('/api/posts',
authenticateJWT, // 1. Authentikáció
requireRole('user'), // 2. Autorizáció
validatePost, // 3. Validáció
uploadImages, // 4. Képfeltöltés
(req, res) => { // 5. Route handler
// Post létrehozás logika
res.json({ message: 'Post created' });
}
);
// Middleware tömb
const postMiddlewares = [
authenticateJWT,
requireRole('user'),
validatePost
];
app.post('/api/posts', postMiddlewares, (req, res) => {
// ...
});
\end{verbatim}
\end{block}
\end{frame}
\begin{frame}{Middleware Best Practices}
\begin{enumerate}
\item \textbf{Sorrend számít:}
\begin{itemize}
\item CORS és security middleware-ek ELŐRE
\item Error handler middleware HÁTRA
\end{itemize}
\vspace{0.2cm}
\item \textbf{Mindig hívd meg a next()-et:}
\begin{itemize}
\item Kivéve ha response-t küldesz vagy hibát dobsz
\end{itemize}
\vspace{0.2cm}
\item \textbf{Error handling:}
\begin{itemize}
\item Async függvényekben try-catch + next(error)
\item 4 paraméteres error handler middleware
\end{itemize}
\vspace{0.2cm}
\item \textbf{Teljesítmény:}
\begin{itemize}
\item Ne futtass middleware-t szükségtelenül (route-specific)
\item Async műveletek csak ha szükséges
\end{itemize}
\vspace{0.2cm}
\item \textbf{Újrafelhasználhatóság:}
\begin{itemize}
\item Middleware factory pattern (pl. requireRole)
\item Konfigurálható middleware-ek
\end{itemize}
\end{enumerate}
\end{frame}
\begin{frame}{Middleware execution order}
\begin{block}{Tipikus middleware sorrend Express alkalmazásban}
\small
\begin{enumerate}
\item \textbf{helmet()} - Security headers
\item \textbf{cors()} - CORS beállítások
\item \textbf{morgan/logger} - Request logging
\item \textbf{express.json()} - Body parser
\item \textbf{express.urlencoded()} - URL-encoded body
\item \textbf{cookie-parser()} - Cookie parsing
\item \textbf{Rate limiter} - API rate limiting
\item \textbf{Custom middlewares} - Saját middleware-ek
\item \textbf{Routes} - Route handler-ek
\item \textbf{404 handler} - Not found middleware
\item \textbf{Error handler} - Központi hibakezelés (4 param)
\end{enumerate}
\end{block}
\end{frame}
\begin{frame}{Összefoglalás - Middleware}
\begin{itemize}
\item \textbf{Middleware} = Függvény a kérés-válasz között
\item \textbf{Paraméterek:} (req, res, next) vagy (err, req, res, next)
\item \textbf{Típusok:} Application, Router, Error-handling, Built-in, Third-party
\item \textbf{next():} Következő middleware-re adja a vezérlést
\item \textbf{Használat:}
\begin{itemize}
\item Logging (morgan, winston)
\item Authentication (JWT validáció)
\item Authorization (szerepkör ellenőrzés)
\item Validation (input ellenőrzés)
\item Rate limiting (express-rate-limit)
\item Security (helmet, cors)
\item Error handling (központi hibakezelés)
\end{itemize}
\item \textbf{Sorrend fontos:} Security → Parsing → Auth → Routes → Error
\end{itemize}
\end{frame}