import { Injectable, ExecutionContext, UnauthorizedException, } from '@nestjs/common'; import { Reflector } from '@nestjs/core'; import { AuthGuard } from '@nestjs/passport'; import { IS_PUBLIC_KEY } from '../decorators/public.decorator'; import { RedisService } from '../../redis/redis.service'; import { JwtPayload } from '../decorators/current-user.decorator'; /** * JwtAuthGuard - Globaler Guard fuer JWT-Authentifizierung. * * - Standardmaessig aktiv auf ALLEN Routen * - @Public() dekorierte Routen werden uebersprungen * - Prueft zusaetzlich ob der Token revoked wurde (Redis Blocklist) */ @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor( private readonly reflector: Reflector, private readonly redis: RedisService, ) { super(); } async canActivate(context: ExecutionContext): Promise { // @Public() Routen ueberspringen const isPublic = this.reflector.getAllAndOverride(IS_PUBLIC_KEY, [ context.getHandler(), context.getClass(), ]); if (isPublic) { return true; } // JWT validieren (Passport Strategy) const canActivate = await super.canActivate(context); if (!canActivate) { return false; } // Token-Revocation pruefen (Redis Blocklist) const request = context.switchToHttp().getRequest(); const user = request.user as JwtPayload; if (user?.jti) { const isBlocked = await this.redis.isTokenBlocked(user.jti); if (isBlocked) { throw new UnauthorizedException('Token wurde widerrufen'); } } return true; } handleRequest(err: Error | null, user: T, info: Error | undefined): T { if (err || !user) { throw err || new UnauthorizedException('Zugriff verweigert'); } return user; } }