Ontwikkel een WebSocket Authenticatie- en Autorisatiesysteem
description
Met deze prompt kun je een veilig authenticatie- en autorisatiesysteem voor je WebSocket verbindingen ontwerpen en implementeren. Dit helpt je om ongeautoriseerde toegang te voorkomen en gebruikersrechten effectief te beheren. Het biedt concrete oplossingen en codevoorbeelden die specifiek zijn afgestemd op jouw technologieën en beveiligingsuitdagingen, waardoor je WebSocket communicatie aanzienlijk veiliger wordt dan met standaardimplementaties.
prompt
Help me met het ontwikkelen van een veilig authenticatie- en autorisatiesysteem voor mijn WebSocket verbindingen. Mijn server technologie: <voer de server technologie in die ik gebruik> Mijn client technologie: <voer de client technologie in die ik gebruik> Mijn gewenste authenticatiemethode (bijv. token, OAuth, JWT): <beschrijf de gewenste authe ...
try_prompt
generate_helper
disclaimerOnPageApi
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hier is een uitgebreide gids met concrete aanbevelingen en codevoorbeelden om een veilig authenticatie- en autorisatiesysteem te implementeren voor je WebSocket-verbindingen met Node.js, Express, React, en JWT.
---
### 1. Algemeen overzicht
- **Authenticatie**: Gebruikers loggen in via een API-endpoint, krijgen een JWT-token.
- **Token beveiliging**: Gebruik HTTPS en beveilig je tokens tegen diefstal (bijv. via beveiligde cookies).
- **WebSocket authenticatie**: Verifieer de JWT bij het opzetten van WebSocket-verbindingen.
- **Autorisatie**: Controleer gebruikersrollen en permissies voordat je bepaalde acties toestaat.
---
### 2. Token genereren en beveiligen
**Server-side (Express):**
```javascript
const jwt = require('jsonwebtoken');
const secretKey = 'je_veilige_zeer_geheime_sleutel'; // Bewaar deze in een omgeving variabele
const expireTime = '1h'; // Pas aan naar je wensen
// Gebruiker login endpoint
app.post('/login', (req, res) => {
const { username, password } = req.body;
// Authenticeer gebruiker (bijvoorbeeld uit database)
const user = authenticateUser(username, password);
if (!user) {
return res.status(401).json({ message: 'Ongeldige inloggegevens' });
}
// Rollen en permissies
const roles = user.roles; // Bijvoorbeeld ['admin', 'editor']
// JWT payload
const payload = {
userId: user.id,
roles: roles,
};
const token = jwt.sign(payload, secretKey, { expiresIn: expireTime });
res.json({ token });
});
```
**React-client:**
Bewaar het token in een beveiligde HTTP-only cookie of in localStorage (met risico). Voor maximale veiligheid, gebruik HTTP-only cookies.
```javascript
// Voorbeeld met fetch en cookies
fetch('/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ username, password }),
credentials: 'include', // Belangrijk bij cookies
})
.then(res => res.json())
.then(data => {
// Token wordt via cookie opgeslagen
});
```
---
### 3. Beveiligde WebSocket verbinding
**Server-side (bijv. met ws of socket.io):**
Stel dat je `socket.io` gebruikt:
```javascript
const io = require('socket.io')(server);
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authenticatie vereist'));
}
jwt.verify(token, secretKey, (err, decoded) => {
if (err) {
return next(new Error('Ongeldige token'));
}
// Voeg gebruikersinfo toe aan socket
socket.user = {
id: decoded.userId,
roles: decoded.roles,
};
next();
});
});
io.on('connection', (socket) => {
console.log(`Gebruiker ${socket.user.id} verbonden`);
});
```
**Client-side (React):**
Bij het verbinden met WebSocket, stuur het JWT:
```javascript
import { io } from 'socket.io-client';
const socket = io('https://jouwdomein.com', {
auth: {
token: 'JE JWT TOKEN HIER',
},
});
```
---
### 4. Autorisatie controleren
Voer controle uit op rollen en permissies binnen je WebSocket events:
```javascript
socket.on('leesData', (data) => {
if (socket.user.roles.includes('reader') || socket.user.roles.includes('admin')) {
// Sta lezen toe
} else {
socket.emit('error', { message: 'Geen leesrechten' });
}
});
```
Voor schrijfbewerkingen:
```javascript
socket.on('schrijfData', (data) => {
if (socket.user.roles.includes('editor') || socket.user.roles.includes('admin')) {
// Bewerkingen toestaan
} else {
socket.emit('error', { message: 'Geen schrijfrechten' });
}
});
```
---
### 5. Extra beveiligingsmaatregelen
- **Gebruik HTTPS**: Zorg dat je hele app via HTTPS draait.
- **HTTP-only cookies**: Sla tokens op in cookies met `HttpOnly` en `Secure` flags.
- **Token vervaldatum**: Beperk de levensduur van tokens (bijv. 1 uur).
- **Refresh tokens**: Implementeer refresh tokens voor langdurige sessies.
- **Token blacklist**: Bij logout of verdachte activiteit, voeg tokens toe aan een blacklist.
- **CSP en CORS**: Beperk domeinen die je WebSocket en API kunnen gebruiken.
---
### 6. Voorbeeld: Token verval en refresh
**Refresh token endpoint:**
```javascript
app.post('/refresh', (req, res) => {
const refreshToken = req.cookies.refreshToken; // of uit body
// Verifieer refresh token
jwt.verify(refreshToken, refreshSecret, (err, decoded) => {
if (err) return res.status(403).json({ message: 'Ongeldige refresh token' });
const newToken = jwt.sign({ userId: decoded.userId, roles: decoded.roles }, secretKey, { expiresIn: '1h' });
res.json({ token: newToken });
});
});
```
---
### 7. Conclusie
- Gebruik JWT met korte vervaltijden.
- Verzend tokens via beveiligde cookies of headers.
- Verifieer tokens bij WebSocket-verbindingen.
- Controleer rollen en permissies binnen je WebSocket-events.
- Beperk en monitor tokengebruik, en implementeer refresh tokens voor betere gebruikerservaring.
---
Heeft u nog specifieke vragen of wilt u een voorbeeld voor een bepaald onderdeel?
provider: deepseek
model: deepseek-chat
Hier is een concrete implementatiegids voor een veilig JWT-gebaseerd authenticatie- en autorisatiesysteem voor WebSocket verbindingen:
## 1. Server-side Implementatie (Node.js/Express)
### JWT Configuratie en Middleware
```javascript
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
// JWT configuratie
const JWT_CONFIG = {
secret: process.env.JWT_SECRET || 'zeer_geheim_wachtwoord_min_32_chars',
expiresIn: '15m', // Korte levensduur voor access tokens
refreshExpiresIn: '7d'
};
// JWT generatie functie
function generateTokens(user) {
const accessToken = jwt.sign(
{
userId: user.id,
role: user.role,
type: 'access'
},
JWT_CONFIG.secret,
{ expiresIn: JWT_CONFIG.expiresIn }
);
const refreshToken = jwt.sign(
{
userId: user.id,
type: 'refresh'
},
JWT_CONFIG.secret,
{ expiresIn: JWT_CONFIG.refreshExpiresIn }
);
return { accessToken, refreshToken };
}
// Authenticatie middleware
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization'];
const token = authHeader && authHeader.split(' ')[1];
if (!token) {
return res.status(401).json({ error: 'Toegangstoken vereist' });
}
jwt.verify(token, JWT_CONFIG.secret, (err, user) => {
if (err) {
return res.status(403).json({ error: 'Ongeldig token' });
}
req.user = user;
next();
});
}
// Autorizatie middleware
function requireRole(role) {
return (req, res, next) => {
if (req.user.role !== role) {
return res.status(403).json({ error: 'Onvoldoende rechten' });
}
next();
};
}
```
### WebSocket Authenticatie (Socket.IO)
```javascript
const { Server } = require('socket.io');
const jwt = require('jsonwebtoken');
function setupWebSocketAuth(server) {
const io = new Server(server, {
cors: {
origin: process.env.CLIENT_URL,
methods: ["GET", "POST"]
}
});
// Authenticatie middleware voor WebSocket
io.use((socket, next) => {
const token = socket.handshake.auth.token;
if (!token) {
return next(new Error('Authenticatie vereist'));
}
jwt.verify(token, JWT_CONFIG.secret, (err, decoded) => {
if (err || decoded.type !== 'access') {
return next(new Error('Ongeldig token'));
}
socket.userId = decoded.userId;
socket.userRole = decoded.role;
next();
});
});
io.on('connection', (socket) => {
console.log(`Gebruiker ${socket.userId} verbonden`);
// Autorizatie per event
socket.on('bericht:verstuur', (data) => {
if (socket.userRole !== 'schrijver' && socket.userRole !== 'admin') {
return socket.emit('error', { message: 'Geen schrijfrechten' });
}
// Verwerk bericht
});
socket.on('bericht:lees', (data) => {
// Iedereen met een geldige token kan lezen
// Verwerk leesverzoek
});
socket.on('disconnect', () => {
console.log(`Gebruiker ${socket.userId} verbroken`);
});
});
return io;
}
```
## 2. Client-side Implementatie (React)
### Auth Context en Hook
```javascript
import React, { createContext, useContext, useState, useEffect } from 'react';
import { io } from 'socket.io-client';
const AuthContext = createContext();
export function AuthProvider({ children }) {
const [user, setUser] = useState(null);
const [socket, setSocket] = useState(null);
const [tokens, setTokens] = useState(() => {
const saved = localStorage.getItem('authTokens');
return saved ? JSON.parse(saved) : null;
});
// WebSocket verbinding opzetten
useEffect(() => {
if (tokens?.accessToken) {
const newSocket = io(process.env.REACT_APP_WS_URL, {
auth: {
token: tokens.accessToken
}
});
newSocket.on('connect_error', (error) => {
if (error.message === 'Authenticatie vereist') {
refreshTokens();
}
});
setSocket(newSocket);
return () => newSocket.close();
}
}, [tokens]);
const login = async (email, password) => {
try {
const response = await fetch('/api/auth/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ email, password })
});
if (!response.ok) throw new Error('Login mislukt');
const { accessToken, refreshToken, user } = await response.json();
const tokenData = { accessToken, refreshToken };
setTokens(tokenData);
setUser(user);
localStorage.setItem('authTokens', JSON.stringify(tokenData));
} catch (error) {
throw error;
}
};
const refreshTokens = async () => {
try {
const response = await fetch('/api/auth/refresh', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ refreshToken: tokens.refreshToken })
});
if (!response.ok) throw new Error('Token vernieuwing mislukt');
const { accessToken, refreshToken } = await response.json();
const newTokens = { accessToken, refreshToken };
setTokens(newTokens);
localStorage.setItem('authTokens', JSON.stringify(newTokens));
} catch (error) {
logout();
}
};
const logout = () => {
setUser(null);
setTokens(null);
setSocket(null);
localStorage.removeItem('authTokens');
};
return (
<AuthContext.Provider value={{ user, socket, login, logout, refreshTokens }}>
{children}
</AuthContext.Provider>
);
}
export const useAuth = () => useContext(AuthContext);
```
## 3. Beveiligingsmaatregelen tegen Token Diefstal
### HTTP-only Cookies voor Refresh Tokens
```javascript
// Server-side cookie configuratie
app.post('/api/auth/login', async (req, res) => {
// ... authenticatie logica
// Stuur refresh token als HTTP-only cookie
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, user });
});
// Token vernieuwing endpoint
app.post('/api/auth/refresh', (req, res) => {
const refreshToken = req.cookies.refreshToken;
if (!refreshToken) {
return res.status(401).json({ error: 'Refresh token vereist' });
}
// Verifieer refresh token en geef nieuw access token
});
```
### Rate Limiting en IP Tracking
```javascript
const rateLimit = require('express-rate-limit');
const authLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minuten
max: 5, // Maximaal 5 pogingen per IP
message: { error: 'Te veel pogingen, probeer later opnieuw' }
});
app.use('/api/auth/', authLimiter);
```
### Token Inroeping (voor verdachte activiteiten)
```javascript
const revokedTokens = new Set();
function revokeToken(token) {
revokedTokens.add(token);
// Verwijder na expiratie
setTimeout(() => revokedTokens.delete(token), 15 * 60 * 1000);
}
// Middleware om ingetrokken tokens te controleren
function checkTokenRevocation(req, res, next) {
const token = req.headers.authorization?.split(' ')[1];
if (revokedTokens.has(token)) {
return res.status(401).json({ error: 'Token ingetrokken' });
}
next();
}
```
## 4. Gebruikersrollen en Permissies
```javascript
// Permissies configuratie
const PERMISSIONS = {
lezer: ['bericht:lees'],
schrijver: ['bericht:lees', 'bericht:verstuur'],
admin: ['bericht:lees', 'bericht:verstuur', 'gebruiker:beheer']
};
// Dynamische autorizatie middleware
function requirePermission(permission) {
return (socket, next) => {
const userPermissions = PERMISSIONS[socket.userRole] || [];
if (!userPermissions.includes(permission)) {
return next(new Error('Onvoldoende rechten'));
}
next();
};
}
// Gebruik in WebSocket events
socket.on('bericht:verstuur', requirePermission('bericht:verstuur'), (data) => {
// Alleen uitgevoerd als gebruiker de juiste permissie heeft
});
```
## 5. Omgevingsvariabelen (.env)
```env
JWT_SECRET=je_zeer_veilige_minimaal_32_karakter_lange_secret
REFRESH_TOKEN_SECRET=andere_veilige_secret_voor_refresh_tokens
CLIENT_URL=https://jouwdomein.nl
NODE_ENV=production
```
## Belangrijke Beveiligingstips:
1. **Gebruik altijd HTTPS** in productie
2. **Implementeer CORS** correct
3. **Valideer alle input** zowel client- als server-side
4. **Log verdachte activiteiten**
5. **Houd dependencies up-to-date**
6. **Gebruik secure flags voor cookies**
7. **Implementeer automatische logout** na inactiviteit
Deze implementatie biedt een robuuste basis voor je authenticatie- en autorisatiesysteem met bescherming tegen token diefstal door middel van korte access token levensduur en veilige refresh token opslag.
error: Generation failed [deepseek] prompt_id=4188 locale=en err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4188 locale=de err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4188 locale=fr err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4188 locale=pt err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4188 locale=es err=DeepSeek connection/timeout | Generation failed [deepseek] prompt_id=4188 locale=zh err=DeepSeek connection/timeout