slogan3

Help me een full-stack project te maken met focus op gebruikersauthenticatie en sessiebeheer.

description

Door te focussen op gebruikersauthenticatie en sessiebeheer, kan ik de beveiliging van mijn applicatie verbeteren, gebruikersgegevens beschermen en een betere gebruikerservaring bieden door efficiënt sessiebeheer.

prompt

try_prompt

Ik wil een full-stack applicatie ontwikkelen met {{frontend_technology}} aan de voorkant en {{backend_technology}} aan de achterkant, met een sterke nadruk op het implementeren van robuuste ... more
generate_helper
disclaimerOnPageApi image_legal_disclaimer...

ai_answers

provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een uitgebreide gids met best practices voor het ontwikkelen van een veilige full-stack applicatie met React en Node.js, gericht op gebruikersauthenticatie en sessiebeheer: 1. **Authenticatiemethoden kiezen** - **JWT (JSON Web Tokens):** Geschikt voor stateless authenticatie. Gebruik korte levensduur en refresh tokens. - **Session-based authentication:** Beheer sessies op de server met cookies. Vooral effectief bij gevoelige data en wanneer servercontrole nodig is. 2. **Beveiligde login en registratie** - **Veilige opslag van wachtwoorden:** Gebruik bcrypt of Argon2 voor hashing met voldoende werkbelasting. - **Inputvalidatie:** Controleer alle invoer aan de client- en serverzijde om SQL-injecties en XSS te voorkomen. - **HTTPS:** Zorg dat alle communicatie via HTTPS verloopt om datadiefstal en man-in-the-middle-aanvallen te voorkomen. - **Captcha:** Overweeg het gebruik van CAPTCHA bij registratie en login om brute-force aanvallen te beperken. 3. **Tokenbeheer en sessiebeheer** - **JWT-beheer:** - Gebruik korte vervaltijden (bijv. 15 minuten) voor access tokens. - Gebruik refresh tokens met een langere vervaltijd (bijv. enkele dagen tot weken). - Beperk de scope van tokens en voeg claims toe voor extra controle. - Behandel tokens als geheime data; sla refresh tokens veilig op (bijvoorbeeld httpOnly, Secure cookies). - **Cookies:** - Gebruik **HttpOnly** en **Secure** cookies voor sessietokens om XSS-aanvallen te verminderen. - Stel SameSite in op 'Strict' of 'Lax' om CSRF-aanvallen te beperken. - Vermijd het opslaan van tokens in localStorage vanwege XSS-gevoeligheid. 4. **Beveiliging tegen aanvallen** - **Cross-Site Request Forgery (CSRF):** - Gebruik CSRF-tokens of SameSite cookies. - Bij gebruik van JWT via cookies, implementeer CSRF-bescherming. - **Cross-Site Scripting (XSS):** - Escape en sanitize alle user-invoer. - Gebruik Content Security Policy (CSP) headers. - **Inhoudsbeveiliging:** - Beperk toegangsrechten op API-niveau met middleware. - Implementeer rolgebaseerde toegangscontrole (RBAC). 5. **Implementatie op de client (React)** - **Authenticatie status beheren:** - Bewaar tokens in HttpOnly cookies of in React state (bij voorkeur cookies). - Gebruik context of state management (zoals Redux) om login status te bewaren. - **Automatisch token vernieuwen:** - Implementeer automatische refresh van tokens bij verval. - Gebruik interceptors (bijv. in axios) om 401-fouten op te vangen en refresh tokens te gebruiken. - **Beveiligde routes:** - Bescherm routes door te controleren op authenticatie en autorisatie. 6. **Server-side implementatie (Node.js)** - **Authenticatie middleware:** - Verifieer tokens en sessies bij elke API-aanroep. - Gebruik libraries zoals Passport.js voor diverse authenticatiemethoden. - **Token en sessie verval:** - Implementeer automatische sessie- of tokenvernieuwing. - Log gebruikers uit na inactiviteit of na vervaldatum. - **Logging en monitoring:** - Log inlogpogingen en verdachte activiteiten. - Implementeer rate limiting om brute-force te voorkomen. 7. **Algemene best practices** - **Versleuteling:** Versleutel gevoelige data in de database. - **Versiebeheer:** Houd je dependencies up-to-date en controleer op beveiligingslekken. - **Security headers:** Voeg security headers toe zoals X-Content-Type-Options, X-Frame-Options en Referrer-Policy. - **Regular security audits:** Voer periodieke code- en beveiligingscontroles uit. --- Door deze best practices te volgen, creëer je een veilige en robuuste gebruikersauthenticatie en sessiebeheer voor je React/Node.js applicatie. Zorg altijd dat je op de hoogte blijft van nieuwe beveiligingsdreigingen en pas je implementatie aan waar nodig.
provider: deepseek
model: deepseek-chat
Zeker! Hier is een uitgebreide gids voor het implementeren van veilige gebruikersauthenticatie en sessiebeheer in een React/Node.js applicatie. ## 1. Architectuur Overzicht ### Frontend (React) - **React 18+** met functionele componenten en hooks - **React Router** voor navigatie - **Axios** voor API calls - **Context API** of **Redux** voor state management ### Backend (Node.js) - **Express.js** framework - **bcrypt** voor wachtwoord hashing - **jsonwebtoken** voor JWT tokens - **cookie-parser** voor cookie management - **helmet** voor security headers ## 2. Backend Implementatie ### Basis Server Setup ```javascript const express = require('express'); const bcrypt = require('bcrypt'); const jwt = require('jsonwebtoken'); const cookieParser = require('cookie-parser'); const helmet = require('helmet'); const app = express(); // Security middleware app.use(helmet()); app.use(express.json()); app.use(cookieParser()); const JWT_SECRET = process.env.JWT_SECRET || 'zeer_geheim_jwt_secret'; const JWT_EXPIRES_IN = '15m'; const REFRESH_TOKEN_SECRET = process.env.REFRESH_TOKEN_SECRET || 'zeer_geheim_refresh_secret'; ``` ### Gebruikersregistratie ```javascript app.post('/api/register', async (req, res) => { try { const { email, wachtwoord, naam } = req.body; // Validatie if (!email || !wachtwoord) { return res.status(400).json({ error: 'Email en wachtwoord zijn verplicht' }); } // Check of gebruiker al bestaat const bestaandeGebruiker = await User.findOne({ email }); if (bestaandeGebruiker) { return res.status(409).json({ error: 'Gebruiker bestaat al' }); } // Wachtwoord hashen const gehashtWachtwoord = await bcrypt.hash(wachtwoord, 12); // Gebruiker aanmaken const nieuweGebruiker = new User({ email, wachtwoord: gehashtWachtwoord, naam }); await nieuweGebruiker.save(); res.status(201).json({ message: 'Gebruiker succesvol aangemaakt', gebruiker: { id: nieuweGebruiker._id, email, naam } }); } catch (error) { res.status(500).json({ error: 'Server error' }); } }); ``` ### Login Endpoint ```javascript app.post('/api/login', async (req, res) => { try { const { email, wachtwoord } = req.body; // Validatie if (!email || !wachtwoord) { return res.status(400).json({ error: 'Email en wachtwoord zijn verplicht' }); } // Gebruiker vinden const gebruiker = await User.findOne({ email }); if (!gebruiker) { return res.status(401).json({ error: 'Ongeldige inloggegevens' }); } // Wachtwoord verifiëren const isWachtwoordCorrect = await bcrypt.compare(wachtwoord, gebruiker.wachtwoord); if (!isWachtwoordCorrect) { return res.status(401).json({ error: 'Ongeldige inloggegevens' }); } // Access Token genereren const accessToken = jwt.sign( { userId: gebruiker._id, email: gebruiker.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ); // Refresh Token genereren const refreshToken = jwt.sign( { userId: gebruiker._id }, REFRESH_TOKEN_SECRET, { expiresIn: '7d' } ); // Refresh token opslaan in database await User.findByIdAndUpdate(gebruiker._id, { refreshToken }); // HTTP-only cookie voor refresh token res.cookie('refreshToken', refreshToken, { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict', maxAge: 7 * 24 * 60 * 60 * 1000 // 7 dagen }); res.json({ accessToken, gebruiker: { id: gebruiker._id, email: gebruiker.email, naam: gebruiker.naam } }); } catch (error) { res.status(500).json({ error: 'Login mislukt' }); } }); ``` ### Token Refresh Endpoint ```javascript app.post('/api/refresh-token', async (req, res) => { try { const refreshToken = req.cookies.refreshToken; if (!refreshToken) { return res.status(401).json({ error: 'Refresh token ontbreekt' }); } // Token verifiëren const decoded = jwt.verify(refreshToken, REFRESH_TOKEN_SECRET); // Gebruiker vinden met refresh token const gebruiker = await User.findOne({ _id: decoded.userId, refreshToken }); if (!gebruiker) { return res.status(401).json({ error: 'Ongeldige refresh token' }); } // Nieuwe access token genereren const nieuweAccessToken = jwt.sign( { userId: gebruiker._id, email: gebruiker.email }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ); res.json({ accessToken: nieuweAccessToken }); } catch (error) { res.status(401).json({ error: 'Ongeldige refresh token' }); } }); ``` ### Authenticatie Middleware ```javascript const authenticateToken = (req, res, next) => { const authHeader = req.headers['authorization']; const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN if (!token) { return res.status(401).json({ error: 'Access token vereist' }); } jwt.verify(token, JWT_SECRET, (err, gebruiker) => { if (err) { return res.status(403).json({ error: 'Ongeldige token' }); } req.gebruiker = gebruiker; next(); }); }; // Beschermde route voorbeeld app.get('/api/protected', authenticateToken, (req, res) => { res.json({ message: 'Dit is beschermde data', gebruiker: req.gebruiker }); }); ``` ### Logout Endpoint ```javascript app.post('/api/logout', authenticateToken, async (req, res) => { try { // Refresh token verwijderen uit database await User.findByIdAndUpdate(req.gebruiker.userId, { refreshToken: null }); // Cookie verwijderen res.clearCookie('refreshToken', { httpOnly: true, secure: process.env.NODE_ENV === 'production', sameSite: 'strict' }); res.json({ message: 'Succesvol uitgelogd' }); } catch (error) { res.status(500).json({ error: 'Logout mislukt' }); } }); ``` ## 3. Frontend Implementatie ### Auth Context ```jsx // contexts/AuthContext.js import React, { createContext, useState, useContext, useEffect } from 'react'; import axios from 'axios'; const AuthContext = createContext(); export const useAuth = () => { const context = useContext(AuthContext); if (!context) { throw new Error('useAuth moet binnen AuthProvider gebruikt worden'); } return context; }; export const AuthProvider = ({ children }) => { const [gebruiker, setGebruiker] = useState(null); const [loading, setLoading] = useState(true); const [accessToken, setAccessToken] = useState(localStorage.getItem('accessToken')); // Axios interceptor voor token refresh useEffect(() => { const requestInterceptor = axios.interceptors.request.use( (config) => { if (accessToken) { config.headers.Authorization = `Bearer ${accessToken}`; } return config; }, (error) => Promise.reject(error) ); const responseInterceptor = axios.interceptors.response.use( (response) => response, async (error) => { const originalRequest = error.config; if (error.response?.status === 401 && !originalRequest._retry) { originalRequest._retry = true; try { const response = await axios.post('/api/refresh-token'); const nieuweToken = response.data.accessToken; setAccessToken(nieuweToken); localStorage.setItem('accessToken', nieuweToken); originalRequest.headers.Authorization = `Bearer ${nieuweToken}`; return axios(originalRequest); } catch (refreshError) { logout(); return Promise.reject(refreshError); } } return Promise.reject(error); } ); return () => { axios.interceptors.request.eject(requestInterceptor); axios.interceptors.response.eject(responseInterceptor); }; }, [accessToken]); // Gebruiker ophalen bij app start useEffect(() => { const initAuth = async () => { if (accessToken) { try { const response = await axios.get('/api/me'); setGebruiker(response.data.gebruiker); } catch (error) { localStorage.removeItem('accessToken'); setAccessToken(null); } } setLoading(false); }; initAuth(); }, [accessToken]); const login = async (email, wachtwoord) => { try { const response = await axios.post('/api/login', { email, wachtwoord }); const { accessToken, gebruiker } = response.data; setAccessToken(accessToken); setGebruiker(gebruiker); localStorage.setItem('accessToken', accessToken); return { success: true }; } catch (error) { return { success: false, error: error.response?.data?.error || 'Login mislukt' }; } }; const logout = async () => { try { await axios.post('/api/logout'); } catch (error) { console.error('Logout error:', error); } finally { setGebruiker(null); setAccessToken(null); localStorage.removeItem('accessToken'); } }; const value = { gebruiker, login, logout, loading }; return ( <AuthContext.Provider value={value}> {children} </AuthContext.Provider> ); }; ``` ### Protected Route Component ```jsx // components/ProtectedRoute.js import { useAuth } from '../contexts/AuthContext'; import { Navigate } from 'react-router-dom'; const ProtectedRoute = ({ children }) => { const { gebruiker, loading } = useAuth(); if (loading) { return <div>Laden...</div>; } return gebruiker ? children : <Navigate to="/login" replace />; }; export default ProtectedRoute; ``` ### Login Component ```jsx // components/Login.js import { useState } from 'react'; import { useAuth } from '../contexts/AuthContext'; const Login = () => { const [email, setEmail] = useState(''); const [wachtwoord, setWachtwoord] = useState(''); const [fout, setFout] = useState(''); const [laden, setLaden] = useState(false); const { login } = useAuth(); const handleSubmit = async (e) => { e.preventDefault(); setLaden(true); setFout(''); const result = await login(email, wachtwoord); if (!result.success) { setFout(result.error); } setLaden(false); }; return ( <div className="login-container"> <form onSubmit={handleSubmit}> <h2>Inloggen</h2> {fout && <div className="fout-melding">{fout}</div>} <div> <label>Email:</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> <div> <label>Wachtwoord:</label> <input type="password" value={wachtwoord} onChange={(e) => setWachtwoord(e.target.value)} required /> </div> <button type="submit" disabled={laden}> {laden ? 'Inloggen...' : 'Inloggen'} </button> </form> </div> ); }; export default Login; ``` ## 4. Beveiligings Best Practices ### Wachtwoord Beveiliging - Gebruik **bcrypt** met minstens 12 rounds - Implementeer wachtwoordsterkte-eisen - Nooit wachtwoorden in logs opslaan ### Token Beveiliging - Korte levensduur access tokens (15-30 minuten) - Refresh tokens in HTTP-only cookies - JWT secret in environment variables - Token blacklist voor uitgelogde gebruikers ### CORS Configuratie ```javascript const cors = require('cors'); app.use(cors({ origin: process.env.FRONTEND_URL || 'http://localhost:3000', credentials: true })); ``` ### Rate Limiting ```javascript const rateLimit = require('express-rate-limit'); const loginLimiter = rateLimit({ windowMs: 15 * 60 * 1000, // 15 minuten max: 5, // maximaal 5 pogingen per windowMs message: 'Te veel inlogpogingen, probeer later opnieuw' }); app.use('/api/login', loginLimiter); ``` ## 5. Environment Variables ```env # .env NODE_ENV=production JWT_SECRET=je_zeer_geheime_jwt_key_hier REFRESH_TOKEN_SECRET=je_zeer_geheime_refresh_key_hier DATABASE_URL=your_database_connection_string FRONTEND_URL=https://jouwdomein.nl ``` ## 6. Deployment Overwegingen - Gebruik **HTTPS** in productie - Stel secure vlag op cookies in productie - Implementeer CSRF bescherming - Gebruik environment variables voor gevoelige data - Houd dependencies up-to-date Deze implementatie biedt een robuuste basis voor gebruikersauthenticatie met goede security practices. Pas de configuraties aan op basis van je specifieke use case en security requirements.
error: Generation failed [deepseek] prompt_id=17549 locale=pt err=DeepSeek connection/timeout