From a837f5ecbad0b870d283dd6170bd6e3d2d91c258 Mon Sep 17 00:00:00 2001 From: magdo Date: Tue, 24 Feb 2026 01:30:22 +0100 Subject: [PATCH] authn_z --- Backend_ppt/authn_z/cookies_old.tex | 470 ----------------- Backend_ppt/authn_z/jwt_old.tex | 549 ------------------- Backend_ppt/authn_z/middlewares_old.tex | 555 -------------------- Backend_ppt/authn_z/oauth2_old.tex | 443 ---------------- Backend_ppt/authn_z/services_old.tex | 671 ------------------------ 5 files changed, 2688 deletions(-) delete mode 100644 Backend_ppt/authn_z/cookies_old.tex delete mode 100644 Backend_ppt/authn_z/jwt_old.tex delete mode 100644 Backend_ppt/authn_z/middlewares_old.tex delete mode 100644 Backend_ppt/authn_z/oauth2_old.tex delete mode 100644 Backend_ppt/authn_z/services_old.tex diff --git a/Backend_ppt/authn_z/cookies_old.tex b/Backend_ppt/authn_z/cookies_old.tex deleted file mode 100644 index af400dd..0000000 --- a/Backend_ppt/authn_z/cookies_old.tex +++ /dev/null @@ -1,470 +0,0 @@ -\section{HTTP Cookies} - -\begin{frame}{Mi az a Cookie?} - \begin{block}{HTTP Cookie definíció} - Kis méretű adat, amit a szerver küld a böngészőnek, és automatikusan vissza küldődik. - \end{block} - - \begin{itemize} - \item \textbf{Méret:} Max 4KB - \item \textbf{Tárolás:} Böngésző - \item \textbf{Élettartam:} Beállítható - - \item \textbf{Használat:} - \begin{itemize} - \item Session kezelés - \item Felhasználói preferenciák - \item Tracking - \end{itemize} - \end{itemize} - - \begin{exampleblock}{Authentikációban} - Cookie-k ideálisak session ID és token tárolására. - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile]{Cookie beállítása} - \begin{block}{Set-Cookie HTTP header} - A szerver a \texttt{Set-Cookie} header segítségével küldi a cookie-t a kliensnek. - \end{block} - - \vspace{0.3cm} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{HTTP válasz:} - \small - \begin{verbatim} -HTTP/1.1 200 OK -Set-Cookie: sessionId=abc123 -Set-Cookie: theme=dark -Content-Type: application/json - -{"success": true} - \end{verbatim} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Node.js/Express:} - \small - \begin{verbatim} -res.cookie('sessionId', 'abc123'); - -res.cookie('theme', 'dark', { - maxAge: 900000, - httpOnly: true -}); - \end{verbatim} - \end{column} - \end{columns} - - \vspace{0.5cm} - - \begin{itemize} - \item A böngésző automatikusan eltárolja a cookie-t - \item Minden későbbi kérésben a böngésző automatikusan visszaküldi - \end{itemize} -\end{frame} - -\begin{frame}[fragile]{Cookie olvasása} - \begin{block}{Cookie HTTP header} - A böngésző minden kérésben visszaküldi a releváns cookie-kat. - \end{block} - - \vspace{0.3cm} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{HTTP kérés:} - \small - \begin{verbatim} -GET /api/user HTTP/1.1 -Host: example.com -Cookie: sessionId=abc123; theme=dark - \end{verbatim} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Node.js/Express:} - \small - \begin{verbatim} -// cookie-parser middleware -const cookieParser = require('cookie-parser'); -app.use(cookieParser()); - -// Cookie olvasás -app.get('/api/user', (req, res) => { - const sessionId = req.cookies.sessionId; - const theme = req.cookies.theme; - - // ... -}); - \end{verbatim} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}{Cookie típusok} - \begin{columns} - \begin{column}{0.48\textwidth} - \begin{block}{Session Cookie} - \begin{itemize} - \item Nincs Expires/Max-Age - \item Böngésző bezárásakor törlődik - \end{itemize} - - \textbf{Használat:} - \begin{itemize} - \item Ideiglenes session - \end{itemize} - \end{block} - \end{column} - - \begin{column}{0.48\textwidth} - \begin{block}{Persistent Cookie} - \begin{itemize} - \item Van Expires/Max-Age - \item Megmarad újraindítás után - \end{itemize} - - \textbf{Használat:} - \begin{itemize} - \item "Remember me" - \item Preferenciák - \end{itemize} - \end{block} - \end{column} - \end{columns} - - \begin{exampleblock}{Példa} - \texttt{Set-Cookie: sessionId=abc123; Max-Age=3600} - \end{exampleblock} -\end{frame} - -\begin{frame}[shrink=5]{Cookie attribútumok} - \begin{enumerate} - \item \textbf{Expires / Max-Age} - \begin{itemize} - \item Expires: Dátum, Max-Age: mper - \end{itemize} - - \item \textbf{Domain} - \begin{itemize} - \item Mely domain-ekhez küldje - \end{itemize} - - \item \textbf{Path} - \begin{itemize} - \item Mely URL path-okhoz - \end{itemize} - - \item \textbf{Secure} - \begin{itemize} - \item Csak HTTPS-en - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}{Biztonsági attribútumok} - \begin{alertblock}{HttpOnly} - \begin{itemize} - \item JavaScript NEM férhet hozzá - \item \textbf{XSS védelem!} - \end{itemize} - \end{alertblock} - - \begin{alertblock}{Secure} - \begin{itemize} - \item Csak HTTPS-en - \item \textbf{MITM védelem!} - \end{itemize} - \end{alertblock} - - \begin{alertblock}{SameSite} - \begin{itemize} - \item Strict - Csak same-site - \item Lax - GET same-site - \item None - Mindenhol (Secure kötelező!) - \item \textbf{CSRF védelem!} - \end{itemize} - \end{alertblock} -\end{frame} - -\begin{frame}[fragile]{Biztonságos cookie beállítás} - \begin{block}{Production környezetben ajánlott beállítások} - \small - \begin{verbatim} -res.cookie('token', jwtToken, { - httpOnly: true, // XSS védelem - JS nem férhet hozzá - secure: true, // Csak HTTPS - production-ben! - sameSite: 'strict', // CSRF védelem - maxAge: 3600000, // 1 óra (milliszekundumban) - path: '/', // Teljes alkalmazásban elérhető - domain: '.example.com' // Domain és aldomain-ek -}); - \end{verbatim} - \end{block} - - \vspace{0.5cm} - - \begin{alertblock}{Kritikus!} - Authentikációs token-ek mindig legyenek \texttt{httpOnly}, \texttt{secure} és \texttt{sameSite} attribútumokkal ellátva! - \end{alertblock} -\end{frame} - -\begin{frame}[shrink=10]{SameSite részletesen} - \begin{block}{CSRF védelem cookie szinten} - SameSite határozza meg, cookie mikor küldhető cross-site kérésekben. - \end{block} - - \begin{enumerate} - \item \textbf{Strict} - \begin{itemize} - \item Csak same-site - \item Legjobb védelem - \end{itemize} - - \item \textbf{Lax} - \begin{itemize} - \item Top-level GET küldődik - \item POST/PUT/DELETE nem - \end{itemize} - - \item \textbf{None} - \begin{itemize} - \item Mindenhol - \item Securekel kötelező! - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}[fragile]{SameSite példák} - \begin{exampleblock}{Példa forgatókönyv} - \texttt{bank.com} oldalon be vagy jelentkezve cookie-val. - Megnyitsz egy \texttt{evil.com} oldalt, ami próbál kérést küldeni \texttt{bank.com}-ra. - \end{exampleblock} - - \vspace{0.3cm} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{SameSite=Strict:} - \small - \begin{verbatim} -Set-Cookie: session=xyz; - SameSite=Strict - \end{verbatim} - - \begin{itemize} - \item \textcolor{red}{$\times$} evil.com $\to$ bank.com POST - \item \textcolor{red}{$\times$} evil.com link $\to$ bank.com - \item \textcolor{green}{$\checkmark$} bank.com $\to$ bank.com - \end{itemize} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{SameSite=Lax:} - \small - \begin{verbatim} -Set-Cookie: session=xyz; - SameSite=Lax - \end{verbatim} - - \begin{itemize} - \item \textcolor{red}{$\times$} evil.com $\to$ bank.com POST - \item \textcolor{green}{$\checkmark$} evil.com link $\to$ bank.com GET - \item \textcolor{green}{$\checkmark$} bank.com $\to$ bank.com - \end{itemize} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,shrink=10]{Cookie törlése} - \begin{block}{Logout - cookie invalidálás} - \small - \begin{verbatim} -app.post('/api/logout', (req, res) => { - res.clearCookie('token', { - httpOnly: true, - secure: true, - sameSite: 'strict' - }); - res.json({ message: 'Logged out' }); -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[shrink=10]{Cookie biztonság - XSS vs CSRF} - \begin{columns} - \begin{column}{0.48\textwidth} - \begin{alertblock}{XSS} - \textbf{Támadás:} - \begin{itemize} - \item JS injektálás - \item Cookie ellopás - \end{itemize} - - \textbf{Védelem:} - \begin{itemize} - \item HttpOnly - \item Input validáció - \item CSP - \end{itemize} - \end{alertblock} - \end{column} - - \begin{column}{0.48\textwidth} - \begin{alertblock}{CSRF} - \textbf{Támadás:} - \begin{itemize} - \item Jogosulatlan kérés - \item Automatikus cookie - \end{itemize} - - \textbf{Védelem:} - \begin{itemize} - \item SameSite - \item CSRF token - \item Origin check - \end{itemize} - \end{alertblock} - \end{column} - \end{columns} - - \begin{block}{Kombinált} - HttpOnly + Secure + SameSite + CSRF token - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10]{CSRF token} - \begin{block}{Double submit pattern} - \small - \begin{verbatim} -const csrf = require('csurf'); -const csrfProtection = csrf({ cookie: { httpOnly: true } }); - -app.use(csrfProtection); - -app.get('/api/csrf-token', (req, res) => { - res.json({ csrfToken: req.csrfToken() }); -}); - -app.post('/api/transfer', (req, res) => { - // CSRF valid automatikus -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10]{Cookie és CORS} - \begin{block}{Cross-Origin} - Cookie-k alapból NEM küldődnek cross-origin-ben. - \end{block} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{Szerver:} - \small - \begin{verbatim} -app.use(cors({ - origin: 'https://frontend.com', - credentials: true -})); - \end{verbatim} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Kliens:} - \small - \begin{verbatim} -fetch('/api/user', { - credentials: 'include' -}) - \end{verbatim} - \end{column} - \end{columns} - - \begin{alertblock}{Fontos!} - credentials: true + 'include' + SameSite=None; Secure - \end{alertblock} -\end{frame} - -\begin{frame}[shrink=10]{Cookie vs localStorage vs sessionStorage} - \begin{small} - \begin{tabular}{|l|c|c|c|} - \hline - & \textbf{Cookie} & \textbf{localStorage} & \textbf{sessionStorage} \\ - \hline - Kapacitás & 4KB & 5-10MB & 5-10MB \\ - \hline - Lejárat & Beállítható & Nincs & Tab bezárás \\ - \hline - HTTP-ben & \textcolor{green}{Igen} & \textcolor{red}{Nem} & \textcolor{red}{Nem} \\ - \hline - XSS védelem & HttpOnly & \textcolor{red}{Nem} & \textcolor{red}{Nem} \\ - \hline - \end{tabular} - \end{small} - - \begin{exampleblock}{Ajánlás} - \textbf{Érzékeny:} HttpOnly Cookie, \textbf{Publikus:} localStorage - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=10]{Signed Cookies} - \begin{block}{Integritás védelem} - HMAC aláírással elliatott cookie, megakadályozza manipulációt. - \end{block} - - \begin{verbatim} -const cookieParser = require('cookie-parser'); -app.use(cookieParser('secret-key')); - -app.get('/set', (req, res) => { - res.cookie('userId', '12345', { signed: true }); - res.send('Set'); -}); - -app.get('/get', (req, res) => { - const userId = req.signedCookies.userId; - res.json({ userId }); -}); - \end{verbatim} -\end{frame} - -\begin{frame}[shrink=5]{Cookie best practices} - \begin{block}{Authentikációs cookie-k} - \begin{enumerate} - \item \textbf{HttpOnly:} JS nem fér hozzá - \item \textbf{Secure:} Csak HTTPS - \item \textbf{SameSite:} Strict/Lax - \item \textbf{Rövid Max-Age:} 15-60 perc - \item \textbf{Path:} Csak szükséges - \item \textbf{Signed cookie:} Manipuláció ellen - \end{enumerate} - \end{block} - - \begin{alertblock}{Production template} - \small - \texttt{res.cookie('token', value, \{httpOnly: true, secure: true, sameSite: 'strict', maxAge: 3600000\})} - \end{alertblock} -\end{frame} - -\begin{frame}[shrink=5]{\u00d6sszefoglalás} - \begin{itemize} - \item \textbf{Cookie} = Kis adat szerver és kliens között - \item \textbf{Típusok:} Session (ideiglenes) vs Persistent - \item \textbf{Attribútumok:} Expires, Domain, Path, Secure, HttpOnly, SameSite - \item textbf{HttpOnly:} XSS védelem - \item \textbf{Secure:} HTTPS - MITM védelem - \item \textbf{SameSite:} CSRF védelem - \item \textbf{CORS:} credentials: true + 'include' - \item \textbf{Biztonság:} HttpOnly + Secure + SameSite - \end{itemize} - - \begin{exampleblock}{Authentikációban} - Cookie a \textbf{legbiztonságosabb} módszer token tárolására. - \end{exampleblock} -\end{frame} - diff --git a/Backend_ppt/authn_z/jwt_old.tex b/Backend_ppt/authn_z/jwt_old.tex deleted file mode 100644 index e515ef0..0000000 --- a/Backend_ppt/authn_z/jwt_old.tex +++ /dev/null @@ -1,549 +0,0 @@ -\section{JWT} - -\begin{frame}{Mi az a JWT?} - \begin{block}{JSON Web Token (RFC 7519)} - Nyílt szabványú, kompakt és önálló módszer információ biztonságos továbbítására. - \end{block} - - \begin{itemize} - \item \textbf{Kompakt:} Kis méret, URL/header-ben is - \item \textbf{Önálló:} Minden információt tartalmaz - \item \textbf{Biztonságos:} Digitálisan aláírt - - \item \textbf{Használat:} - \begin{itemize} - \item Authentikáció - \item Információ csere - \item Stateless session - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,shrink=10]{JWT formátum} - \begin{block}{Három részből áll, ponttal elválasztva} - \texttt{\textcolor{red}{HEADER}.\textcolor{purple}{PAYLOAD}.\textcolor{blue}{SIGNATURE}} - \end{block} - - \begin{exampleblock}{Példa JWT} - \tiny - \begin{verbatim} -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZ -SI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36P -OkmLXOUqhfKJ4 - \end{verbatim} - \end{exampleblock} - - \begin{itemize} - \item \textcolor{red}{\textbf{Header:}} Token típusa és algoritmus - \item \textcolor{purple}{\textbf{Payload:}} Claims (állítások) - felhasználói adatok - \item \textcolor{blue}{\textbf{Signature:}} Aláírás - integritás ellenőrzés - \end{itemize} - - \begin{alertblock}{Fontos!} - A JWT Base64URL kódolású, \textbf{NEM} titkosított! A payload tartalma olvasható! - \end{alertblock} -\end{frame} - -\begin{frame}[fragile]{JWT Header} - \begin{block}{Token metaadatok} - Token típusa és aláírási algoritmus. - \end{block} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{JSON:} - \begin{verbatim} -{ - "alg": "HS256", - "typ": "JWT" -} - \end{verbatim} - - \begin{itemize} - \item \texttt{alg}: Algoritmus - \item \texttt{typ}: Token típus - \end{itemize} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Kódolt:} - \begin{verbatim} -eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 - \end{verbatim} - - \textbf{Algoritmusok:} - \begin{itemize} - \item HS256 - HMAC - \item RS256 - RSA - \item ES256 - ECDSA - \end{itemize} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile,shrink=5]{JWT Payload (Claims)} - \begin{block}{Felhasználói adatok és meta} - Claims (allítoltak) a felhasználóról és tokenről. - \end{block} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{Registered:} - \begin{itemize} - \item \texttt{iss} - Kibocsátó - \item \texttt{sub} - Tárgy/user ID - \item \texttt{aud} - Címzett - \item \texttt{exp} - Lejárat - \item \texttt{iat} - Kiállítás - \end{itemize} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Példa:} - \small - \begin{verbatim} -{ - "sub": "1234567890", - "name": "John Doe", - "role": "admin", - "iat": 1516239022, - "exp": 1516242622 -} - \end{verbatim} - \end{column} - \end{columns} - - \begin{alertblock}{Figyelem!} - Ne tároljunk érzékeny adatokat (jelszó) payload-ban! - \end{alertblock} -\end{frame} - -\begin{frame}[fragile,shrink=5]{JWT Signature} - \begin{block}{Digitális aláírás} - Biztosítja a token integritását és hitelességét. - \end{block} - - \textbf{Signature (HMAC SHA256):} - \begin{verbatim} -HMACSHA256( - base64UrlEncode(header) + "." + base64UrlEncode(payload), - secret -) - \end{verbatim} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{HMAC (Symmetric):} - \begin{itemize} - \item Egy kulcs - \item Gyorsabb - \item HS256 - \end{itemize} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{RSA (Asymmetric):} - \begin{itemize} - \item Privát + publikus - \item Biztonságosabb - \item RS256 - \end{itemize} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}{JWT működése} - \begin enumerate} - \item \textbf{Bejelentkezés:} - \begin{itemize} - \item Username + password - \item Szerver validál - \end{itemize} - - \item \textbf{Token generálás:} - \begin{itemize} - \item JWT létrehozás user adatokkal - \item Aláírás titkos kulccsal - \end{itemize} - - \item \textbf{Tárolás:} - \begin{itemize} - \item localStorage / cookie - \end{itemize} - - \item \textbf{API kérések:} - \begin{itemize} - \item \texttt{Authorization: Bearer } - \item Szerver validálja - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}[fragile,shrink=10]{JWT generálás Node.js-ben} - \begin{block}{jsonwebtoken könyvtár használata} - \small - \begin{verbatim} -const jwt = require('jsonwebtoken'); - -const payload = { - userId: user.id, - email: user.email, - role: user.role -}; - -const token = jwt.sign( - payload, - process.env.JWT_SECRET, - { expiresIn: '1h', issuer: 'myapp' } -); - -res.json({ token, expiresIn: 3600 }); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10]{JWT validálás Node.js-ben} - \begin{block}{Token ellenőrzés} - \small - \begin{verbatim} -const authHeader = req.headers.authorization; -const token = authHeader?.split(' ')[1]; - -if (!token) { - return res.status(401).json({ error: 'No token' }); -} - -try { - const decoded = jwt.verify(token, process.env.JWT_SECRET); - req.user = decoded; - next(); -} catch (error) { - return res.status(403).json({ error: 'Invalid' }); -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10]{JWT middleware Express-ben} - \begin{block}{Védett route-ok} - \small - \begin{verbatim} -const authenticateJWT = (req, res, next) => { - const token = req.headers.authorization?.split(' ')[1]; - - if (!token) return res.status(401).json({ error: 'Token required' }); - - jwt.verify(token, process.env.JWT_SECRET, (err, user) => { - if (err) return res.status(403).json({ error: 'Invalid token' }); - req.user = user; - next(); - }); -}; - -app.get('/api/protected', authenticateJWT, (req, res) => { - res.json({ message: 'Protected', user: req.user }); -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}{JWT vs Session} - \begin{columns} - \begin{column}{0.48\textwidth} - \begin{block}{JWT (Stateless)} - \textbf{Előnyök:} - \begin{itemize} - \item Skálázható - \item Nincs szerver-oldali tárolás - \item Cross-domain működés - \item Mobile-friendly - \end{itemize} - - \vspace{0.3cm} - - \textbf{Hátrányok:} - \begin{itemize} - \item Nehéz visszavonni - \item Token méret - \item XSS sebezhetőség (localStorage) - \end{itemize} - \end{block} - \end{column} - - \begin{column}{0.48\textwidth} - \begin{block}{Session (Stateful)} - \textbf{Előnyök:} - \begin{itemize} - \item Azonnali visszavonás - \item Kis cookie méret - \item Biztonságosabb token tárolás - \end{itemize} - - \vspace{0.3cm} - - \textbf{Hátrányok:} - \begin{itemize} - \item Szerver-oldali memória - \item Nehezebb skálázás - \item CORS problémák - \item Session store szükséges - \end{itemize} - \end{block} - \end{column} - \end{columns} - - \vspace{0.5cm} - - \begin{alertblock}{Melyiket válasszuk?} - Függ az alkalmazás követelményeitől: méret, skálázhatóság, biztonság, komplexitás. - \end{alertblock} -\end{frame} - -\begin{frame}{Token tárolás a kliens oldalon} - \begin{columns} - \begin{column}{0.48\textwidth} - \begin{block}{localStorage} - \begin{itemize} - \item Egyszerű - \item JS hozzáférés - \item Megosztott - \end{itemize} - - \textcolor{red}{\textbf{XSS!}} - \begin{itemize} - \item \textcolor{red}{JS hozzáférhet} - \end{itemize} - \end{block} - \end{column} - - \begin{column}{0.48\textwidth} - \begin{block}{HttpOnly Cookie} - \begin{itemize} - \item JS NEM fér hozzá - \item Automatikus - \item XSS védett - \end{itemize} - - \textcolor{red}{\textbf{CSRF}} - \begin{itemize} - \item \textcolor{red}{Védelem kell} - \end{itemize} - \end{block} - \end{column} - \end{columns} - - \begin{exampleblock}{Ajánlás} - HttpOnly, Secure, SameSite cookie a legbiztonságosabb. - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile]{JWT tárolás HttpOnly Cookie-ban} - \begin{block}{Token beállítás cookie-ban} - \small - \begin{verbatim} -// Login endpoint -app.post('/api/login', (req, res) => { - // ... authentikáció logika ... - - const token = jwt.sign(payload, secret, { expiresIn: '1h' }); - - res.cookie('token', token, { - httpOnly: true, // JavaScript nem férhet hozzá - secure: true, // Csak HTTPS-en keresztül - sameSite: 'strict',// CSRF védelem - maxAge: 3600000 // 1 óra milliszekundumban - }); - - res.json({ success: true, message: 'Logged in' }); -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{JWT olvasás Cookie-ból} - \begin{block}{Cookie-parser middleware} - \small - \begin{verbatim} -const cookieParser = require('cookie-parser'); -app.use(cookieParser()); - -const authenticateJWT = (req, res, next) => { - // Token a cookie-ból - const token = req.cookies.token; - - if (!token) { - return res.status(401).json({ error: 'Not authenticated' }); - } - - try { - const decoded = jwt.verify(token, process.env.JWT_SECRET); - req.user = decoded; - next(); - } catch (error) { - return res.status(403).json({ error: 'Invalid token' }); - } -}; - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[shrink=5]{Refresh Token stratégia} - \begin{block}{Miért szükséges?} - Access tokenek rövidek (15 perc). Refresh tokennel új access token kérhető. - \end{block} - - \begin{itemize} - \item \textbf{Access Token:} - \begin{itemize} - \item Rövid (15-60 perc) - \item API kérésekhez - \end{itemize} - - \item \textbf{Refresh Token:} - \begin{itemize} - \item Hosszú (7-30 nap) - \item Új access tokenhez - \item HttpOnly cookie-ban - \item DB-ben tárolva - \end{itemize} - \end{itemize} - - \begin{alertblock}{Best Practice} - Refresh token rotation: minden refresh-nél új refresh token is. - \end{alertblock} -\end{frame} - -\begin{frame}[fragile]{Refresh Token implementáció} - \begin{block}{Token refresh endpoint} - \small - \begin{verbatim} -app.post('/api/refresh', (req, res) => { - const refreshToken = req.cookies.refreshToken; - - if (!refreshToken) { - return res.status(401).json({ error: 'No refresh token' }); - } - - try { - // Refresh token validálás - const decoded = jwt.verify(refreshToken, process.env.REFRESH_SECRET); - - // Ellenőrizzük az adatbázisban - const storedToken = await RefreshToken.findOne({ - token: refreshToken, - userId: decoded.userId - }); - - if (!storedToken) { - return res.status(403).json({ error: 'Invalid refresh token' }); - } - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Refresh Token implementáció (folyt.)} - \begin{block}{Új tokenek generálása} - \small - \begin{verbatim} - // Új access token - const accessToken = jwt.sign( - { userId: decoded.userId, role: decoded.role }, - process.env.JWT_SECRET, - { expiresIn: '15m' } - ); - - // Új refresh token (rotation) - const newRefreshToken = jwt.sign( - { userId: decoded.userId }, - process.env.REFRESH_SECRET, - { expiresIn: '7d' } - ); - - // Régi token törlése, új mentése az adatbázisba - await RefreshToken.deleteOne({ token: refreshToken }); - await RefreshToken.create({ token: newRefreshToken, userId: decoded.userId }); - - res.cookie('refreshToken', newRefreshToken, { httpOnly: true, ... }); - res.json({ accessToken }); - } catch (error) { - res.status(403).json({ error: 'Invalid refresh token' }); - } -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[shrink=5]{JWT biztonság best practices} - \begin{alertblock}{Kritikus pontok} - \begin{itemize} - \item \textbf{Titkos kulcs:} Erős, random, env-ben - \item \textbf{HTTPS:} Mindig! - \item \textbf{Lejárat:} Max 1 óra - \item \textbf{Érzeky adatok:} Ne JWT-ben - \item \textbf{Algoritmus:} Ellenőrizd (ne 'none') - \end{itemize} - \end{alertblock} - - \begin{block}{További ajánlások} - \begin{itemize} - \item HttpOnly cookie - \item Refresh token rotation - \item Rate limiting - \item Aud és Iss validálás - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}{Gyakori JWT hibák és támadások} - \begin{alertblock}{Gyakori sebezhetőségek} - \begin{enumerate} - \item \textbf{None algoritmus támadás} - \begin{itemize} - \item Header: \texttt{"alg": "none"} - aláírás nélküli token - \item Védelem: Mindig ellenőrizzük az algoritmust - \end{itemize} - - \item \textbf{Gyenge titkos kulcs} - \begin{itemize} - \item Rövid vagy közismert kulcs - \item Védelem: Min. 256-bit random kulcs - \end{itemize} - - \item \textbf{Token kiszivárogtatás} - \begin{itemize} - \item XSS támadás localStorage-ból - \item Védelem: HttpOnly cookie használata - \end{itemize} - - \item \textbf{Algoritmus konfúzió} - \begin{itemize} - \item RS256 publikus kulcs HMAC secret-ként használva - \item Védelem: Explicit algoritmus megadása validáláskor - \end{itemize} - \end{enumerate} - \end{alertblock} -\end{frame} - -\begin{frame}{Összefoglalás} - \begin{itemize} - \item \textbf{JWT} = Kompakt, önálló, biztonságos token formátum - \item \textbf{Struktúra:} Header.Payload.Signature - \item \textbf{Előnyök:} Stateless, skálázható, cross-domain - \item \textbf{Claims:} Registered (exp, iat, sub) és Custom (role, email) - \item \textbf{Tárolás:} HttpOnly cookie a legbiztonságosabb - \item \textbf{Refresh token:} Új access token kéréshez hosszú élettartammal - \item \textbf{Biztonság:} HTTPS, erős secret, rövid lejárat, validálás - \end{itemize} - - \vspace{0.5cm} - - \begin{exampleblock}{Mikor használjuk a JWT-t?} - \begin{itemize} - \item RESTful API authentikáció - \item Microservice architektúra - \item Mobile alkalmazások - \item Single Page Applications (SPA) - \item Stateless session kezelés - \end{itemize} - \end{exampleblock} -\end{frame} diff --git a/Backend_ppt/authn_z/middlewares_old.tex b/Backend_ppt/authn_z/middlewares_old.tex deleted file mode 100644 index 563759e..0000000 --- a/Backend_ppt/authn_z/middlewares_old.tex +++ /dev/null @@ -1,555 +0,0 @@ -\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} diff --git a/Backend_ppt/authn_z/oauth2_old.tex b/Backend_ppt/authn_z/oauth2_old.tex deleted file mode 100644 index ddc9af2..0000000 --- a/Backend_ppt/authn_z/oauth2_old.tex +++ /dev/null @@ -1,443 +0,0 @@ -\section{OAuth 2.0} - -\begin{frame}{Mi az OAuth 2.0?} - \begin{block}{Definíció} - OAuth 2.0 egy nyílt szabványú \textbf{autorizációs protokoll}, amely korlátozott hozzáférést ad jelszó megosztása nélkül. - \end{block} - - \begin{itemize} - \item RFC 6749 (2012) - \item Autorizációra fókuszál - \item Biztonságos delegált hozzáférés - \item Google, Facebook, GitHub - \end{itemize} - - \begin{exampleblock}{Használat} - Alkalmazás hozzáfér Google Drive-hoz anélkül, hogy ismebné a jelszót. - \end{exampleblock} -\end{frame} - -\begin{frame}{OAuth 2.0 szerepkörök} - \begin{enumerate} - \item \textbf{Resource Owner (Erőforrás tulajdonos)} - \begin{itemize} - \item A felhasználó, aki birtokolja az erőforrást - \item Engedélyezheti a hozzáférést - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Client (Kliens)} - \begin{itemize} - \item Az alkalmazás, amely hozzáférést kér az erőforráshoz - \item Például: mobil app, webalkalmazás - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Authorization Server (Autorizációs szerver)} - \begin{itemize} - \item Kiállítja az access token-t sikeres authentikáció után - \item Kezeli a felhasználói hozzájárulást - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Resource Server (Erőforrás szerver)} - \begin{itemize} - \item Tárolja a védett erőforrásokat - \item Elfogadja és validálja az access token-eket - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}{OAuth 2.0 Flow - Áttekintés} - \begin{center} - \begin{tikzpicture}[node distance=2cm, auto] - \node (ro) [rectangle, draw, text width=2cm, text centered] {Resource Owner}; - \node (client) [rectangle, draw, below of=ro, text width=2cm, text centered] {Client}; - \node (authserver) [rectangle, draw, right of=client, xshift=3cm, text width=2.5cm, text centered] {Authorization Server}; - \node (resserver) [rectangle, draw, below of=authserver, text width=2.5cm, text centered] {Resource Server}; - - \draw[->, thick] (client) -- node[left] {1. Kérés} (ro); - \draw[->, thick] (ro) -- node[above] {2. Hozzájárulás} (authserver); - \draw[->, thick] (authserver) -- node[right] {3. Token} (client); - \draw[->, thick] (client) -- node[above] {4. API kérés} (resserver); - \draw[->, thick] (resserver) -- node[below] {5. Védett erőforrás} (client); - \end{tikzpicture} - \end{center} - - \begin{itemize} - \item Az Authorization Server és Resource Server lehet ugyanaz a rendszer - \item A kommunikáció HTTPS-en keresztül történik - \end{itemize} -\end{frame} - -\begin{frame}[shrink=10]{OAuth 2.0 Grant Types} - \begin{block}{Grant Type} - Módszer, ahogyan kliens access token-t szerez. - \end{block} - - \begin{enumerate} - \item \textbf{Authorization Code} - \begin{itemize} - \item Legbiztonságosabb, szerveroldali app-hoz - \end{itemize} - - \item \textbf{Implicit} - \begin{itemize} - \item \textcolor{red}{Elavult!} - \end{itemize} - - \item \textbf{Resource Owner Password} - \begin{itemize} - \item Közvetlen jelszó, megbízható app-okhoz - \end{itemize} - - \item \textbf{Client Credentials} - \begin{itemize} - \item Machine-to-machine - \end{itemize} - - \item \textbf{PKCE} - \begin{itemize} - \item Modern mobil és SPA-hoz - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}[shrink=10]{Authorization Code Flow} - \begin{block}{Leggyakrabban használt flow} - Biztonságos szerveroldali alkalmazásokhoz, ahol a client secret biztonságosan tárolható. - \end{block} - - \begin{enumerate} - \small - \item \textbf{Kliens átirányítja a felhasználót} az Authorization Server-re - \begin{itemize} - \item URL: \texttt{/authorize?client\_id=\&redirect\_uri=\&scope=\&state=} - \end{itemize} - - \item \textbf{Felhasználó bejelentkezik és hozzájárul} - - \item \textbf{Authorization Server visszairányít} authorization code-dal - \begin{itemize} - \item URL: \texttt{redirect\_uri?code=AUTH\_CODE\&state=} - \end{itemize} - - \item \textbf{Kliens kicseréli a code-ot} access token-re - \begin{itemize} - \item POST: \texttt{/token} (client\_id, client\_secret, code, redirect\_uri) - \end{itemize} - - \item \textbf{Authorization Server visszaad} access token-t (és refresh token-t) - - \item \textbf{Kliens használja az access token-t} API kérésekhez - \end{enumerate} -\end{frame} - -\begin{frame}[fragile,shrink=10]{Authorization Code Flow - Példa} - \begin{block}{1. Felhasználó átirányítása az authorization endpoint-ra} - \small - \begin{verbatim} -GET /oauth/authorize? - response_type=code& - client_id=YOUR_CLIENT_ID& - redirect_uri=https://yourapp.com/callback& - scope=read write& - state=xyz123 - \end{verbatim} - \end{block} - - \begin{block}{2. Callback authorization code-dal} - \small - \begin{verbatim} -GET https://yourapp.com/callback? - code=AUTH_CODE_HERE& - state=xyz123 - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile,shrink=10]{Authorization Code Flow - Példa (folyt.)} - \begin{block}{3. Token kérés} - \small - \begin{verbatim} -POST /oauth/token -Content-Type: application/x-www-form-urlencoded - -grant_type=authorization_code& -code=AUTH_CODE_HERE& -redirect_uri=https://yourapp.com/callback& -client_id=YOUR_CLIENT_ID& -client_secret=YOUR_CLIENT_SECRET - \end{verbatim} - \end{block} - - \begin{block}{4. Token válasz} - \small - \begin{verbatim} -{ - "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", - "token_type": "Bearer", - "expires_in": 3600, - "refresh_token": "tGzv3JOkF0XG5Qx2TlKWIA", - "scope": "read write" -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}{PKCE (Proof Key for Code Exchange)} - \begin{block}{Miért szükséges?} - A natív és SPA (Single Page Application) alkalmazások nem tudják biztonságosan tárolni a client secret-et. A PKCE authorization code interception elleni védelmet nyújt. - \end{block} - - \vspace{0.5cm} - - \begin{enumerate} - \item Kliens generál egy random \textbf{code\_verifier} értéket - \item Létrehoz egy \textbf{code\_challenge}-t a verifier-ből - \begin{itemize} - \item \texttt{code\_challenge = BASE64URL(SHA256(code\_verifier))} - \end{itemize} - \item Authorization kéréshez csatolja a \texttt{code\_challenge}-t - \item Token kéréshez csatolja a \texttt{code\_verifier}-t - \item Szerver ellenőrzi, hogy a verifier megfelel-e a challenge-nek - \end{enumerate} - - \vspace{0.5cm} - - \begin{alertblock}{Fontos!} - A PKCE ma már \textbf{minden} OAuth 2.0 flow-hoz ajánlott! - \end{alertblock} -\end{frame} - -\begin{frame}{Client Credentials Grant} - \begin{block}{Machine-to-Machine hitelesítés} - Amikor nincs felhasználói interakció, csak két rendszer kommunikál egymással. - \end{block} - - \vspace{0.5cm} - - \begin{itemize} - \item \textbf{Használati esetek:} - \begin{itemize} - \item Backend szolgáltatások közötti kommunikáció - \item Cron job-ok, scheduled task-ok - \item CLI eszközök - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Folyamat:} - \begin{enumerate} - \item Kliens küld egy POST kérést a token endpoint-ra - \item Csatolja a client\_id-t és client\_secret-et - \item Szerver visszaadja az access token-t - \item Kliens használja a token-t API kérésekhez - \end{enumerate} - \end{itemize} - - \vspace{0.3cm} - - \begin{alertblock}{Figyelem!} - Nincs refresh token, mert nincs felhasználói kontextus! - \end{alertblock} -\end{frame} - -\begin{frame}[fragile]{Client Credentials Grant - Példa} - \begin{block}{Token kérés} - \small - \begin{verbatim} -POST /oauth/token -Content-Type: application/x-www-form-urlencoded -Authorization: Basic BASE64(client_id:client_secret) - -grant_type=client_credentials& -scope=api.read - \end{verbatim} - \end{block} - - \vspace{0.3cm} - - \begin{block}{Token válasz} - \small - \begin{verbatim} -{ - "access_token": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", - "token_type": "Bearer", - "expires_in": 3600, - "scope": "api.read" -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Access Token és Refresh Token} - \begin{columns} - \begin{column}{0.48\textwidth} - \begin{block}{Access Token} - \begin{itemize} - \item Rövid élettartam (pl. 1 óra) - \item API kérésekhez használt - \item Bearer token formátum - \item Gyakran JWT - \end{itemize} - \end{block} - - \vspace{0.3cm} - - \textbf{Használat:} - \small - \begin{verbatim} -Authorization: Bearer - ACCESS_TOKEN - \end{verbatim} - \end{column} - - \begin{column}{0.48\textwidth} - \begin{block}{Refresh Token} - \begin{itemize} - \item Hosszú élettartam (napok/hetek) - \item Új access token kéréséhez - \item Biztonságosan tárolva - \item Opaque token - \end{itemize} - \end{block} - - \vspace{0.3cm} - - \textbf{Token megújítás:} - \small - \begin{verbatim} -POST /oauth/token -grant_type=refresh_token& -refresh_token=REFRESH_TOKEN - \end{verbatim} - \end{column} - \end{columns} - - \vspace{0.5cm} - - \begin{alertblock}{Best Practice} - Az access token lejárta esetén a refresh token-nel új tokent kérünk, nem kell újra bejelentkeztetni a felhasználót! - \end{alertblock} -\end{frame} - -\begin{frame}{Scopes (Hatókörök)} - \begin{block}{Mi az a scope?} - A \textbf{scope} meghatározza, hogy a kliens milyen erőforrásokhoz és milyen műveletekhez férhet hozzá. - \end{block} - - \vspace{0.5cm} - - \begin{itemize} - \item \textbf{Granulált jogosultságok:} - \begin{itemize} - \item \texttt{read} - olvasási jogosultság - \item \texttt{write} - írási jogosultság - \item \texttt{delete} - törlési jogosultság - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Erőforrás specifikus:} - \begin{itemize} - \item \texttt{user:email} - email cím olvasása - \item \texttt{repo:write} - repository írása - \item \texttt{profile:read} - profil olvasása - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Best Practices:} - \begin{itemize} - \item Least privilege principle: csak a szükséges scope-ok - \item Egyértelmű elnevezés - \item Dokumentáció minden scope-hoz - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}{OpenID Connect (OIDC)} - \begin{block}{Authentikációs réteg OAuth 2.0 felett} - Az \textbf{OpenID Connect} kiegészíti az OAuth 2.0-t authentikációs funkcionalitással. - \end{block} - - \vspace{0.5cm} - - \begin{itemize} - \item \textbf{OAuth 2.0} = Autorizáció - \item \textbf{OpenID Connect} = Autorizáció + Authentikáció - - \vspace{0.3cm} - - \item \textbf{ID Token:} - \begin{itemize} - \item JWT formátumú token - \item Tartalmazza a felhasználó azonosító adatait - \item Claims: \texttt{sub}, \texttt{name}, \texttt{email}, \texttt{picture}, stb. - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{UserInfo Endpoint:} - \begin{itemize} - \item További felhasználói információk lekérdezése - \item Access token-nel hívható - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Használat:} "Sign in with Google", "Login with Facebook" - \end{itemize} -\end{frame} - -\begin{frame}{OAuth 2.0 Biztonsági best practices} - \begin{alertblock}{Kritikus biztonsági szempontok} - \begin{itemize} - \item \textbf{HTTPS kötelező} minden kommunikációhoz! - \item \textbf{State paraméter} használata CSRF védelem miatt - \item \textbf{Client secret} biztonságos tárolása (szerver oldalon) - \item \textbf{Redirect URI validáció} - csak engedélyezett URI-k - \item \textbf{Token lejárati idő} beállítása - \item \textbf{Scope minimalizálása} - least privilege - \end{itemize} - \end{alertblock} - - \vspace{0.3cm} - - \begin{block}{További ajánlások} - \begin{itemize} - \item PKCE használata minden flow-ban - \item Token revocation támogatása - \item Rate limiting az endpoint-okon - \item Token tárolás biztonságos helyen (HttpOnly cookie) - \item Regular security audit - \end{itemize} - \end{block} -\end{frame} - -\begin{frame}{Összefoglalás} - \begin{itemize} - \item \textbf{OAuth 2.0} = Autorizációs protokoll (nem authentikációs!) - \item \textbf{Szerepkörök:} Resource Owner, Client, Authorization Server, Resource Server - \item \textbf{Grant Types:} Authorization Code (PKCE), Client Credentials - \item \textbf{Tokenek:} Access Token (rövid), Refresh Token (hosszú) - \item \textbf{Scopes:} Granulált jogosultság kezelés - \item \textbf{OpenID Connect:} OAuth 2.0 + Authentikáció - \item \textbf{Biztonság:} HTTPS, state, PKCE, token biztonság - \end{itemize} - - \vspace{0.5cm} - - \begin{exampleblock}{Amikor OAuth 2.0-t használunk} - \begin{itemize} - \item Social login implementációhoz - \item Third-party API hozzáféréshez - \item Microservice authentikációhoz - \item Mobile és SPA alkalmazásokhoz - \end{itemize} - \end{exampleblock} -\end{frame} diff --git a/Backend_ppt/authn_z/services_old.tex b/Backend_ppt/authn_z/services_old.tex deleted file mode 100644 index 6550e6b..0000000 --- a/Backend_ppt/authn_z/services_old.tex +++ /dev/null @@ -1,671 +0,0 @@ -\section{Service Layer} - -\begin{frame}[shrink=5]{Mi az a Service Layer?} - \begin{block}{Definíció} - A \textbf{Service Layer} (szolgáltatási réteg) egy tervezési minta, amely elválasztja az üzleti logikát a controller-ektől és a data access layer-től. - \end{block} - - \begin{itemize} - \item \textbf{Separation of Concerns:} Felelősségek szétválasztása - \item \textbf{Reusability:} Újrafelhasználható üzleti logika - \item \textbf{Testability:} Könnyebb tesztelhetőség - \item \textbf{Maintainability:} Karbantarthatóság - \end{itemize} - - \begin{exampleblock}{MVC architektúrában} - Controller → \textbf{Service Layer} → Repository/Model → Database - \end{exampleblock} -\end{frame} - -\begin{frame}[shrink=5]{Háromrétegű architektúra} - \begin{columns} - \begin{column}{0.3\textwidth} - \begin{block}{Presentation Layer} - \begin{itemize} - \item Controllers - \item Routes - \item HTTP kérés/válasz - \item Validáció - \end{itemize} - \end{block} - \end{column} - - \begin{column}{0.35\textwidth} - \begin{block}{Business Logic Layer} - \begin{itemize} - \item \textbf{Services} - \item Üzleti szabályok - \item Adatmanipuláció - \item Orchestration - \end{itemize} - \end{block} - \end{column} - - \begin{column}{0.3\textwidth} - \begin{block}{Data Access Layer} - \begin{itemize} - \item Repository - \item Models - \item ORM - \item Database - \end{itemize} - \end{block} - \end{column} - \end{columns} - - \begin{alertblock}{Fontos!} - A controller \textbf{NEM} tartalmaz üzleti logikát, csak delegál a service-eknek! - \end{alertblock} -\end{frame} - -\begin{frame}[shrink=10]{Service Layer előnyei} - \begin{enumerate} - \item \textbf{Separation of Concerns} - \begin{itemize} - \item Tiszta felelősségi körök - \item Controller: HTTP kezelés - \item Service: Üzleti logika - \item Repository: Adatelérés - \end{itemize} - - \item \textbf{Reusability} - \begin{itemize} - \item Több controller használhatja ugyanazt a service-t - \item Különböző kontextusokban (API, CLI, Background job) - \end{itemize} - - \item \textbf{Testability} - \begin{itemize} - \item Service-ek könnyebben unit tesztelhetők - \item Mock-olható függőségek - \end{itemize} - - \item \textbf{Maintainability} - \begin{itemize} - \item Változások izoláltak - \item Könnyebb hibakeresés - \end{itemize} - \end{enumerate} -\end{frame} - -\begin{frame}[fragile,shrink=5]{AuthService - Authentikációs szolgáltatás} - \begin{block}{AuthService felelősségei} - \begin{itemize} - \item Felhasználó regisztráció - \item Bejelentkezés (login) - \item Token generálás és validálás - \item Jelszó hash-elés - \item Kijelentkezés (logout) - \end{itemize} - \end{block} - - \begin{exampleblock}{AuthService példa} - \small - \begin{verbatim} -class AuthService { - async register(userData) { ... } - async login(email, password) { ... } - async logout(userId) { ... } - async refreshToken(refreshToken) { ... } - async verifyToken(token) { ... } - async resetPassword(email) { ... } -} - \end{verbatim} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=10]{AuthService implementáció - Register} - \begin{block}{Regisztráció üzleti logikája} - \small - \begin{verbatim} -class AuthService { - async register(userData) { - const existing = await this.userRepository - .findByEmail(userData.email); - if (existing) throw new Error('User exists'); - - const hashed = await bcrypt.hash(userData.password, 10); - const user = await this.userRepository.create({ - ...userData, - password: hashed - }); - - return { id: user.id, email: user.email }; - } -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{AuthService implementáció - Login} - \begin{block}{Bejelentkezés üzleti logikája} - \small - \begin{verbatim} -async login(email, password) { - const user = await this.userRepository.findByEmail(email); - if (!user) throw new Error('Invalid credentials'); - - const valid = await bcrypt.compare(password, user.password); - if (!valid) throw new Error('Invalid credentials'); - - const accessToken = jwt.sign( - { userId: user.id, email: user.email }, - process.env.JWT_SECRET, { expiresIn: '15m' } - ); - - const refreshToken = jwt.sign( - { userId: user.id }, - process.env.REFRESH_SECRET, { expiresIn: '7d' } - ); - - return { accessToken, refreshToken }; -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Controller használja az AuthService-t} - \begin{block}{Thin Controller - Fat Service} - \small - \begin{verbatim} -app.post('/api/auth/register', async (req, res) => { - try { - const user = await authService.register(req.body); - res.status(201).json({ user }); - } catch (error) { - res.status(400).json({ error: error.message }); - } -}); - -app.post('/api/auth/login', async (req, res) => { - try { - const result = await authService.login( - req.body.email, req.body.password - ); - res.cookie('refreshToken', result.refreshToken, - { httpOnly: true, secure: true }); - res.json({ accessToken: result.accessToken }); - } catch (error) { - res.status(401).json({ error: error.message }); - } -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{UserService - Felhasználó kezelés} - \begin{block}{UserService felelősségei} - \begin{itemize} - \item Felhasználói profil lekérdezés - \item Profil módosítás - \item Jelszó változtatás - \item Felhasználó törlés - \item Felhasználó lista (admin) - \end{itemize} - \end{block} - - \vspace{0.3cm} - - \begin{exampleblock}{UserService példa} - \small - \begin{verbatim} -class UserService { - constructor(userRepository) { - this.userRepository = userRepository; - } - - async getUserProfile(userId) { ... } - async updateProfile(userId, data) { ... } - async changePassword(userId, oldPassword, newPassword) { ... } - async deleteUser(userId) { ... } - async getAllUsers(filters) { ... } -} - \end{verbatim} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=5]{UserService implementáció} - \begin{block}{Jelszó változtatás üzleti logikával} - \small - \begin{verbatim} -class UserService { - async changePassword(userId, oldPass, newPass) { - const user = await this.userRepository.findById(userId); - if (!user) throw new Error('User not found'); - - const valid = await bcrypt.compare(oldPass, user.password); - if (!valid) throw new Error('Incorrect password'); - - const hashed = await bcrypt.hash(newPass, 10); - await this.userRepository.update(userId, - { password: hashed }); - await this.tokenService.revokeAllTokens(userId); - - return { success: true }; - } -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{TokenService - Token kezelés} - \begin{block}{TokenService felelősségei} - \begin{itemize} - \item Access token generálás - \item Refresh token generálás - \item Token validálás - \item Token megújítás (refresh) - \item Token visszavonás (revoke) - \end{itemize} - \end{block} - - \vspace{0.3cm} - - \begin{exampleblock}{TokenService példa} - \small - \begin{verbatim} -class TokenService { - constructor(tokenRepository) { - this.tokenRepository = tokenRepository; - } - - generateAccessToken(payload) { ... } - generateRefreshToken(userId) { ... } - async verifyAccessToken(token) { ... } - async refreshAccessToken(refreshToken) { ... } - async revokeToken(token) { ... } - async revokeAllTokens(userId) { ... } -} - \end{verbatim} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile,shrink=5]{TokenService implementáció} - \begin{block}{Token refresh implementáció} - \small - \begin{verbatim} -class TokenService { - async refreshAccessToken(refreshToken) { - const decoded = jwt.verify( - refreshToken, process.env.REFRESH_SECRET); - - const stored = await this.tokenRepository - .findByToken(refreshToken); - if (!stored || stored.revoked) - throw new Error('Token revoked'); - - const user = await this.userRepository - .findById(decoded.userId); - return { - accessToken: this.generateAccessToken(user) - }; - } -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{AuthorizationService - Autorizáció} - \begin{block}{AuthorizationService felelősségei} - \begin{itemize} - \item Jogosultság ellenőrzés - \item Role-based access control (RBAC) - \item Permission-based access control (PBAC) - \item Resource ownership ellenőrzés - \end{itemize} - \end{block} - - \vspace{0.3cm} - - \begin{exampleblock}{AuthorizationService példa} - \small - \begin{verbatim} -class AuthorizationService { - async hasRole(userId, role) { ... } - async hasPermission(userId, permission) { ... } - async canAccessResource(userId, resourceId, action) { ... } - async isOwner(userId, resourceId) { ... } -} - \end{verbatim} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile]{AuthorizationService implementáció} - \begin{block}{Jogosultság ellenőrzés} - \small - \begin{verbatim} -class AuthorizationService { - constructor(userRepository, permissionRepository) { - this.userRepository = userRepository; - this.permissionRepository = permissionRepository; - } - - async canAccessResource(userId, resourceId, action) { - const user = await this.userRepository.findById(userId); - - // 1. Admin mindent csinálhat - if (user.role === 'admin') { - return true; - } - - // 2. Ownership ellenőrzés - const resource = await this.resourceRepository.findById(resourceId); - if (resource.ownerId === userId && action === 'read') { - return true; - } - - // 3. Permission alapú ellenőrzés - const permissions = await this.permissionRepository.getByUserId(userId); - return permissions.some(p => p.action === action && p.resource === resourceId); - } -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Dependency Injection} - \begin{block}{Service-ek kapcsolata} - A service-ek más service-eket használnak. Dependency Injection segít a függőségek kezelésében. - \end{block} - - \vspace{0.3cm} - - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{Rossz példa:} - \small - \begin{verbatim} -class AuthService { - constructor() { - this.userRepo = - new UserRepository(); - } -} - \end{verbatim} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Jó példa (DI):} - \small - \begin{verbatim} -class AuthService { - constructor(userRepo) { - this.userRepo = userRepo; - } -} - -const authService = - new AuthService(userRepo); - \end{verbatim} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}[fragile]{Service Container / DI Container} - \begin{block}{Automatikus Dependency Injection} - DI container-ek automatikusan kezelik a szolgáltatások létrehozását. - \end{block} - - \vspace{0.3cm} - - \begin{exampleblock}{Awilix library használata} - \small - \begin{verbatim} -const { createContainer, asClass } = require('awilix'); - -const container = createContainer(); -container.register({ - userRepository: asClass(UserRepository).singleton(), - tokenRepository: asClass(TokenRepository).singleton(), - authService: asClass(AuthService).singleton(), - userService: asClass(UserService).singleton(), - tokenService: asClass(TokenService).singleton() -}); - -const authService = container.resolve('authService'); - \end{verbatim} - \end{exampleblock} -\end{frame} - -\begin{frame}[fragile]{Error Handling a Service Layer-ben} - \begin{block}{Custom Error osztályok} - \small - \begin{verbatim} -class AuthenticationError extends Error { - constructor(message) { - super(message); - this.statusCode = 401; - } -} - -class AuthorizationError extends Error { - constructor(message) { - super(message); - this.statusCode = 403; - } -} - -class NotFoundError extends Error { - constructor(resource) { - super(`${resource} not found`); - this.statusCode = 404; - } -} - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Error Handling - Service használat} - \begin{block}{Service dobja a custom error-t} - \small - \begin{verbatim} -class AuthService { - async login(email, password) { - const user = await this.userRepository - .findByEmail(email); - if (!user) { - throw new AuthenticationError('Invalid credentials'); - } - const valid = await bcrypt.compare( - password, user.password - ); - if (!valid) { - throw new AuthenticationError('Invalid credentials'); - } - // ... - } -} - \end{verbatim} - \end{block} - - \vspace{0.2cm} - - \begin{block}{Controller kezeli} - \small - \begin{verbatim} -app.post('/api/auth/login', async (req, res, next) => { - try { - const result = await authService.login( - req.body.email, req.body.password); - res.json(result); - } catch (error) { - next(error); - } -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}[fragile]{Global Error Handler Middleware} - \begin{block}{Központi hibaüzenet kezelés} - \small - \begin{verbatim} -app.use((error, req, res, next) => { - console.error(error); - - if (error.statusCode) { - return res.status(error.statusCode) - .json({ error: error.message }); - } - - res.status(500).json({ - error: 'Internal Server Error' - }); -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}{Service Layer Testing} - \begin{block}{Unit Testing} - A service-ek izoláltan tesztelhetők mock repository-kkal és service-ekkel. - \end{block} - - \vspace{0.3cm} - - \begin{itemize} - \item \textbf{Előnyök:} - \begin{itemize} - \item Gyors tesztek (nincs adatbázis) - \item Üzleti logika fókusz - \item Mock-olható függőségek - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Test framework-ök:} - \begin{itemize} - \item Jest - \item Mocha + Chai - \item Vitest - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Mocking library-k:} - \begin{itemize} - \item Sinon.js - \item Jest built-in mocks - \end{itemize} - \end{itemize} -\end{frame} - -\begin{frame}[fragile,shrink=5]{Service Unit Test példa} - \begin{block}{AuthService.login() teszt} - \small - \begin{verbatim} -describe('AuthService', () => { - let authService, mockUserRepo; - - beforeEach(() => { - mockUserRepo = { findByEmail: jest.fn() }; - authService = new AuthService(mockUserRepo); - }); - - test('login fails for invalid user', async () => { - mockUserRepo.findByEmail.mockResolvedValue(null); - await expect( - authService.login('test@test.com', 'pass') - ).rejects.toThrow('Invalid credentials'); - }); -}); - \end{verbatim} - \end{block} -\end{frame} - -\begin{frame}{Service Layer Best Practices} - \begin{enumerate} - \item \textbf{Single Responsibility:} Egy service egy felelősségi kör - \item \textbf{Dependency Injection:} Konstruktorban injektált függőségek - \item \textbf{Thin Controllers:} Controller csak HTTP kezel - \item \textbf{Error Handling:} Custom error osztályok használata - \item \textbf{Async/Await:} Tiszta aszinkron kód - \item \textbf{Validation:} Input validáció a service-ben is - \item \textbf{Transaction Management:} Adatbázis tranzakciók - \item \textbf{Logging:} Strukturált log-olás - \end{enumerate} -\end{frame} - -\begin{frame}{Projekt struktúra Service Layer-rel} - \begin{columns} - \begin{column}{0.48\textwidth} - \textbf{Fájl struktúra:} - \small - \begin{itemize} - \item \texttt{src/} - \begin{itemize} - \item \texttt{controllers/} - \begin{itemize} - \item \texttt{auth.controller.js} - \item \texttt{user.controller.js} - \end{itemize} - \item \texttt{services/} - \begin{itemize} - \item \texttt{auth.service.js} - \item \texttt{user.service.js} - \item \texttt{token.service.js} - \end{itemize} - \item \texttt{repositories/} - \begin{itemize} - \item \texttt{user.repository.js} - \item \texttt{token.repository.js} - \end{itemize} - \item \texttt{models/} - \item \texttt{middlewares/} - \item \texttt{utils/} - \end{itemize} - \end{itemize} - \end{column} - - \begin{column}{0.48\textwidth} - \textbf{Rétegek felelősségei:} - \begin{itemize} - \item \textbf{Controller:} - \begin{itemize} - \item HTTP kérés/válasz - \item Validáció (input) - \item Service hívás - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Service:} - \begin{itemize} - \item Üzleti logika - \item Adatmanipuláció - \item Orchestration - \end{itemize} - - \vspace{0.3cm} - - \item \textbf{Repository:} - \begin{itemize} - \item Adatbázis műveletek - \item Query-k - \item ORM interaction - \end{itemize} - \end{itemize} - \end{column} - \end{columns} -\end{frame} - -\begin{frame}{Összefoglalás} - \begin{itemize} - \item \textbf{Service Layer} = Üzleti logika réteg - \item \textbf{Separation of Concerns:} Controller, Service, Repository - \item \textbf{AuthService:} Regisztráció, login, token kezelés - \item \textbf{UserService:} Felhasználó kezelés, profil, jelszó - \item \textbf{TokenService:} Token generálás, validálás, refresh - \item \textbf{AuthorizationService:} Jogosultság ellenőrzés - \item \textbf{Dependency Injection:} Konstruktor alapú DI - \item \textbf{Error Handling:} Custom error osztályok - \item \textbf{Testing:} Unit teszt mock-okkal - \item \textbf{Best Practices:} Thin controller, fat service - \end{itemize} - - \vspace{0.3cm} - - \begin{exampleblock}{Miért használjuk?} - Tiszta kód, újrafelhasználhatóság, tesztelhetőség, karbantarthatóság - \end{exampleblock} -\end{frame}