import { Inject, Injectable, UnauthorizedException } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { ConfigService } from '@nestjs/config'; import { JwtPayload } from '../models/jwt-payload.model'; import { UserRepository } from '../../auth/users/UserRepository'; import { RedisClientToken } from '../../core/configs/cache/redis-client.adapter.provider'; import { IRedisClient } from '../../core/configs/cache/IRedisClient'; import { TokenBlacklistService } from '../services/token-blacklist.service'; import { SessionManagementService } from '../services/session-management.service'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( @Inject(RedisClientToken) private readonly redis: IRedisClient, private readonly userRepository: UserRepository, private readonly configService: ConfigService, private readonly tokenBlacklistService: TokenBlacklistService, private readonly sessionManagementService: SessionManagementService, ) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), secretOrKey: configService.get('jwtSecret'), }); } async validate(payload: JwtPayload, req: any) { if (!payload?.id || !payload?.sessionId) { throw new UnauthorizedException('Payload inválido ou incompleto'); } const token = req.headers?.authorization?.replace('Bearer ', ''); if (token && (await this.tokenBlacklistService.isBlacklisted(token))) { throw new UnauthorizedException('Token foi invalidado'); } const sessionKey = this.buildSessionKey(payload.id, payload.sessionId); const cachedUser = await this.redis.get(sessionKey); if (cachedUser) { const isSessionActive = await this.sessionManagementService.isSessionActive( payload.id, payload.sessionId, ); if (!isSessionActive) { throw new UnauthorizedException('Sessão expirada ou inválida'); } return { id: cachedUser.id, sellerId: cachedUser.sellerId, storeId: cachedUser.storeId, username: cachedUser.username, email: cachedUser.email, name: cachedUser.name, sessionId: payload.sessionId, }; } const user = await this.userRepository.findById(payload.id); if (!user || user.situacao === 'I' || user.dataDesligamento) { throw new UnauthorizedException('Usuário inválido ou inativo'); } if (user.situacao === 'B') { throw new UnauthorizedException( 'Usuário bloqueado, acesso não permitido', ); } const userData = { id: user.id, sellerId: user.sellerId, storeId: user.storeId, username: user.name, email: user.email, name: user.name, sessionId: payload.sessionId, }; await this.redis.set(sessionKey, userData, 60 * 60 * 8); return userData; } private buildSessionKey(userId: number, sessionId: string): string { return `auth:sessions:${userId}:${sessionId}`; } }