93 lines
3.0 KiB
TypeScript
93 lines
3.0 KiB
TypeScript
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<string>('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<any>(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}`;
|
|
}
|
|
}
|