Hoe kan ik een aangepaste middleware-oplossing implementeren in TypeScript voor {{middleware_type}}?
description
Door deze prompt te volgen, verbeteren gebruikers de architectuur van hun toepassing door effectieve middleware-implementatie, wat leidt tot betere onderhoudbaarheid, schaalbaarheid en codehergebruik.
prompt
try_prompt
Help me een aangepaste middleware-oplossing in TypeScript maken die {{middleware_type}} scenario's kan afhandelen. Geef gedetailleerde stappen, co ... more
generate_helper
...
tags
ai_answers
provider: openai
model: gpt-4.1-nano
Natuurlijk! Hieronder vind je een stapsgewijze handleiding om een flexibele en herbruikbare middleware-oplossing voor authenticatie in TypeScript te maken. Deze aanpak zorgt voor goede structuur, onderhoudbaarheid en hergebruik in je toepassing.
---
## 1. Structuur en Best Practices
- **Modules scheiden**: Plaats authenticatie-logica, middleware en configuratie in aparte mappen/bestanden.
- **Type-beheer**: Gebruik TypeScript types en interfaces voor duidelijkheid en type-veiligheid.
- **Configuratie**: Maak gebruik van configuratiebestanden voor verschillende authenticatiescenario's.
- **Herbruikbaarheid**: Bouw middleware die flexibel is en kan worden aangepast aan verschillende authenticatiescenario's.
- **Error handling**: Zorg voor consistente en duidelijke foutmeldingen.
---
## 2. Stap-voor-stap implementatie
### a) Set-up project en dependencies
Gebruik bijvoorbeeld een Node.js project met Express:
```bash
npm init -y
npm install express @types/express typescript ts-node
```
Maak een `tsconfig.json` voor TypeScript configuratie.
---
### b) Definieer types en interfaces
Maak een bestand `types.ts`:
```typescript
// src/types.ts
export interface IUser {
id: string;
username: string;
roles?: string[];
}
export interface AuthenticatedRequest extends Express.Request {
user?: IUser;
}
```
---
### c) Authentificatiemiddleware basis
Maak een basis middleware `authMiddleware.ts`:
```typescript
// src/middleware/authMiddleware.ts
import { Request, Response, NextFunction } from 'express';
import { AuthenticatedRequest, IUser } from '../types';
type AuthFunction = (req: Request) => Promise<IUser | null>;
export function createAuthMiddleware(authFn: AuthFunction) {
return async (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
try {
const user = await authFn(req);
if (!user) {
return res.status(401).json({ message: 'Niet geautoriseerd' });
}
req.user = user;
next();
} catch (error) {
console.error('Authentatiefout:', error);
res.status(500).json({ message: 'Serverfout tijdens authenticatie' });
}
};
}
```
Deze factory maakt middleware met een custom authenticatiefunctie.
---
### d) Implementatie van authenticatiefuncties
Voorbeeld 1: Token-gebaseerde authenticatie (bijv. JWT):
```typescript
// src/auth/jwtAuth.ts
import { Request } from 'express';
import jwt from 'jsonwebtoken';
import { IUser } from '../types';
const SECRET_KEY = 'jouw-secret';
export const jwtAuth = async (req: Request): Promise<IUser | null> => {
const authHeader = req.headers['authorization'];
if (!authHeader || !authHeader.startsWith('Bearer ')) return null;
const token = authHeader.substring(7, authHeader.length);
try {
const payload = jwt.verify(token, SECRET_KEY) as any;
return {
id: payload.sub,
username: payload.username,
roles: payload.roles,
};
} catch {
return null;
}
};
```
---
### e) Middleware gebruiken
In je server setup:
```typescript
// src/server.ts
import express from 'express';
import { createAuthMiddleware } from './middleware/authMiddleware';
import { jwtAuth } from './auth/jwtAuth';
const app = express();
const authMiddleware = createAuthMiddleware(jwtAuth);
app.use('/api/protected', authMiddleware, (req: any, res) => {
res.json({ message: `Welkom, ${req.user?.username}` });
});
app.listen(3000, () => console.log('Server draait op poort 3000'));
```
---
## 3. Uitgebreide scenario's en best practices
- **Meerdere authenticatiemethoden**: Maak verschillende `authFn` functies en combineer ze indien nodig.
- **Rolgebaseerde toegang**: Voeg middleware toe die rollen controleert:
```typescript
export function authorizeRoles(...allowedRoles: string[]) {
return (req: AuthenticatedRequest, res: Response, next: NextFunction) => {
const userRoles = req.user?.roles || [];
const hasRole = allowedRoles.some(role => userRoles.includes(role));
if (!hasRole) {
return res.status(403).json({ message: 'Toegang geweigerd' });
}
next();
};
}
```
Gebruik dit na authenticatie:
```typescript
app.use('/admin', authMiddleware, authorizeRoles('admin'), (req, res) => {
res.send('Admin toegang');
});
```
- **Herbruikbare middleware**: Maak combinaties, bijvoorbeeld:
```typescript
app.use('/admin', authMiddleware, authorizeRoles('admin'), (req, res) => { ... });
```
- **Logging en foutafhandeling**: Voeg logging toe voor debugging en monitoring.
---
## 4. Samenvatting
- Gebruik een `createAuthMiddleware` factory voor herbruikbare authenticatie.
- Scheid authenticatiefuncties per scenario (JWT, API key, etc.).
- Voeg rol- of permissiecontrole toe als extra middleware.
- Houd types strikt voor betere codekwaliteit.
- Documenteer je middleware en gebruik consistente foutafhandeling.
---
Mocht je nog meer specifieke scenario's of codevoorbeelden willen, laat het gerust weten!
provider: deepseek
model: deepseek-chat
Zeker! Ik help je een aangepaste middleware-oplossing voor authenticatie in TypeScript te bouwen. Hier is een complete handleiding met gedetailleerde stappen, codevoorbeelden en best practices.
## 1. Projectstructuur en Dependencies
Eerst instellen we de basisstructuur:
```
src/
├── middleware/
│ ├── auth.middleware.ts
│ ├── types.ts
│ └── index.ts
├── utils/
│ └── jwt.utils.ts
├── types/
│ └── express.ts
└── app.ts
```
**Package.json dependencies:**
```json
{
"dependencies": {
"express": "^4.18.0",
"jsonwebtoken": "^9.0.0",
"bcryptjs": "^2.4.3"
},
"devDependencies": {
"@types/express": "^4.17.0",
"@types/jsonwebtoken": "^9.0.0",
"@types/bcryptjs": "^2.4.0",
"typescript": "^5.0.0"
}
}
```
## 2. Type Definitions
```typescript
// src/types/express.ts
import { Request } from 'express';
export interface AuthenticatedUser {
userId: string;
email: string;
roles: string[];
}
declare global {
namespace Express {
interface Request {
user?: AuthenticatedUser;
}
}
}
// src/middleware/types.ts
export interface AuthConfig {
secret: string;
expiresIn: string;
requiredRoles?: string[];
}
export interface AuthMiddlewareOptions {
requireAuth?: boolean;
requiredRoles?: string[];
allowPublic?: boolean;
}
```
## 3. JWT Utility Functions
```typescript
// src/utils/jwt.utils.ts
import jwt from 'jsonwebtoken';
import { AuthenticatedUser } from '../types/express';
export class JWTUtils {
private static readonly SECRET = process.env.JWT_SECRET || 'jouw-geheime-sleutel';
private static readonly EXPIRES_IN = '7d';
static generateToken(user: Omit<AuthenticatedUser, 'roles'> & { roles: string[] }): string {
return jwt.sign(
{
userId: user.userId,
email: user.email,
roles: user.roles
},
this.SECRET,
{ expiresIn: this.EXPIRES_IN }
);
}
static verifyToken(token: string): AuthenticatedUser | null {
try {
const decoded = jwt.verify(token, this.SECRET) as AuthenticatedUser;
return decoded;
} catch (error) {
return null;
}
}
static extractTokenFromHeader(authHeader: string | undefined): string | null {
if (!authHeader || !authHeader.startsWith('Bearer ')) {
return null;
}
return authHeader.substring(7);
}
}
```
## 4. Hoofd Authenticatie Middleware
```typescript
// src/middleware/auth.middleware.ts
import { Request, Response, NextFunction } from 'express';
import { JWTUtils } from '../utils/jwt.utils';
import { AuthMiddlewareOptions } from './types';
export class AuthMiddleware {
/**
* Basis authenticatie middleware
*/
static authenticate(options: AuthMiddlewareOptions = {}) {
return (req: Request, res: Response, next: NextFunction): void => {
const { requireAuth = true, requiredRoles = [], allowPublic = false } = options;
// Token extractie
const token = JWTUtils.extractTokenFromHeader(req.headers.authorization);
// Geen token gevonden
if (!token) {
if (allowPublic && !requireAuth) {
return next();
}
if (!requireAuth) {
return next();
}
return this.sendError(res, 401, 'Authenticatie vereist');
}
// Token verifiëren
const user = JWTUtils.verifyToken(token);
if (!user) {
return this.sendError(res, 401, 'Ongeldig of verlopen token');
}
// Gebruiker toevoegen aan request
req.user = user;
// Rol-based autorisatie controleren
if (requiredRoles.length > 0 && !this.hasRequiredRoles(user.roles, requiredRoles)) {
return this.sendError(res, 403, 'Onvoldoende rechten');
}
next();
};
}
/**
* Rol-specifieke middleware factory
*/
static requireRoles(roles: string[]) {
return this.authenticate({ requiredRoles: roles, requireAuth: true });
}
/**
* Optionele authenticatie middleware
*/
static optionalAuth() {
return this.authenticate({ requireAuth: false, allowPublic: true });
}
/**
* Admin-only middleware
*/
static requireAdmin() {
return this.requireRoles(['admin']);
}
/**
* Helper: Rol check
*/
private static hasRequiredRoles(userRoles: string[], requiredRoles: string[]): boolean {
return requiredRoles.some(role => userRoles.includes(role));
}
/**
Helper: Error response
*/
private static sendError(res: Response, status: number, message: string): void {
res.status(status).json({
success: false,
error: {
code: status,
message: message
}
});
}
}
```
## 5. Aanvullende Security Middleware
```typescript
// src/middleware/security.middleware.ts
import { Request, Response, NextFunction } from 'express';
export class SecurityMiddleware {
/**
* Rate limiting middleware
*/
static rateLimit(requestsPerMinute: number = 100) {
const requests = new Map<string, number[]>();
return (req: Request, res: Response, next: NextFunction): void => {
const ip = req.ip || 'unknown';
const now = Date.now();
const windowStart = now - 60000; // 1 minuut
// Oude requests opruimen
const userRequests = requests.get(ip) || [];
const recentRequests = userRequests.filter(time => time > windowStart);
// Rate limit check
if (recentRequests.length >= requestsPerMinute) {
res.status(429).json({
success: false,
error: {
code: 429,
message: 'Te veel requests'
}
});
return;
}
// Nieuwe request toevoegen
recentRequests.push(now);
requests.set(ip, recentRequests);
next();
};
}
/**
* CORS middleware
*/
static cors(allowedOrigins: string[] = ['*']) {
return (req: Request, res: Response, next: NextFunction): void => {
const origin = req.headers.origin;
if (allowedOrigins.includes('*') || (origin && allowedOrigins.includes(origin))) {
res.header('Access-Control-Allow-Origin', origin || '*');
res.header('Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, OPTIONS');
res.header('Access-Control-Allow-Headers', 'Content-Type, Authorization');
res.header('Access-Control-Allow-Credentials', 'true');
}
if (req.method === 'OPTIONS') {
res.sendStatus(200);
return;
}
next();
};
}
}
```
## 6. Middleware Export en Configuratie
```typescript
// src/middleware/index.ts
export { AuthMiddleware } from './auth.middleware';
export { SecurityMiddleware } from './security.middleware';
export type { AuthMiddlewareOptions } from './types';
```
## 7. Gebruik in Express Applicatie
```typescript
// src/app.ts
import express from 'express';
import { AuthMiddleware, SecurityMiddleware } from './middleware';
const app = express();
// Global middleware
app.use(express.json());
app.use(SecurityMiddleware.cors(['http://localhost:3000']));
app.use(SecurityMiddleware.rateLimit(100));
// Routes met verschillende authenticatie niveaus
app.get('/public', AuthMiddleware.optionalAuth(), (req, res) => {
const userInfo = req.user ? `Ingelogd als: ${req.user.email}` : 'Anonieme gebruiker';
res.json({ message: 'Publieke route', user: userInfo });
});
app.get('/protected', AuthMiddleware.authenticate(), (req, res) => {
res.json({
message: 'Beschermde route',
user: req.user
});
});
app.get('/admin', AuthMiddleware.requireAdmin(), (req, res) => {
res.json({
message: 'Admin route',
user: req.user
});
});
app.get('/user-data', AuthMiddleware.requireRoles(['user', 'admin']), (req, res) => {
res.json({
message: 'User data route',
user: req.user
});
});
// Error handling middleware
app.use((error: Error, req: express.Request, res: express.Response, next: express.NextFunction) => {
console.error('Middleware error:', error);
res.status(500).json({
success: false,
error: {
code: 500,
message: 'Interne serverfout'
}
});
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server draait op poort ${PORT}`);
});
```
## 8. Gebruiksvoorbeeld met Login
```typescript
// src/routes/auth.routes.ts
import express from 'express';
import { JWTUtils } from '../utils/jwt.utils';
import bcrypt from 'bcryptjs';
const router = express.Router();
// Mock user database
const mockUsers = [
{
id: '1',
email: 'admin@voorbeeld.nl',
password: '$2a$10$voorbeeldhashedpassword', // "wachtwoord123"
roles: ['admin', 'user']
}
];
router.post('/login', async (req, res) => {
const { email, password } = req.body;
// Validatie
if (!email || !password) {
return res.status(400).json({
success: false,
error: 'Email en wachtwoord zijn vereist'
});
}
// User zoeken
const user = mockUsers.find(u => u.email === email);
if (!user) {
return res.status(401).json({
success: false,
error: 'Ongeldige inloggegevens'
});
}
// Wachtwoord verifiëren (in praktijk: bcrypt.compare)
const isValidPassword = await bcrypt.compare(password, user.password);
if (!isValidPassword) {
return res.status(401).json({
success: false,
error: 'Ongeldige inloggegevens'
});
}
// Token genereren
const token = JWTUtils.generateToken({
userId: user.id,
email: user.email,
roles: user.roles
});
res.json({
success: true,
data: {
token,
user: {
id: user.id,
email: user.email,
roles: user.roles
}
}
});
});
export default router;
```
## Best Practices en Aanbevelingen
### 1. **Security Best Practices**
- Gebruik environment variables voor secrets
- Implementeer token refresh mechanisme
- Gebruik HTTPS in productie
- Hash wachtwoorden met bcrypt
- Implementeer CSRF protection
### 2. **Middleware Structuur**
- Houd middleware focused en single-purpose
- Gebruik factory pattern voor configureerbare middleware
- Documenteer elk middleware component
- Implementeer goede error handling
### 3. **TypeScript Best Practices**
- Gebruik interfaces voor request extensies
- Implementeer custom types voor auth data
- Gebruik generics waar mogelijk
- Valideer incoming data met libraries zoals Zod
### 4. **Performance Overwegingen**
- Cache veelgebruikte auth checks
- Implementeer connection pooling voor database
- Gebruik efficiente token verification
- Monitor middleware performance
### 5. **Testing Strategy**
```typescript
// Voorbeeld test
import request from 'supertest';
import { app } from '../app';
describe('Auth Middleware', () => {
it('should block unauthorized access', async () => {
const response = await request(app)
.get('/protected')
.expect(401);
expect(response.body.error.message).toBe('Authenticatie vereist');
});
});
```
Deze structuur biedt een solide basis voor authenticatie middleware die eenvoudig is uit te breiden, te testen en te onderhouden. Pas de configuratie aan naar jouw specifieke use case en security requirements.

