feat: implementar melhorias na autenticação

- Adicionar refresh tokens para renovação automática de tokens
- Implementar controle de sessões simultâneas
- Adicionar blacklist de tokens para logout seguro
- Implementar rate limiting para proteção contra ataques
- Melhorar detecção de IP e identificação de sessão atual
- Adicionar endpoints para gerenciamento de sessões
- Corrigir inconsistências na validação de usuário
- Atualizar configuração Redis com nova conexão
This commit is contained in:
Joelson
2025-09-16 18:17:37 -03:00
parent 055f138e5a
commit 21c3225c52
33 changed files with 1061 additions and 1375 deletions

View File

@@ -7,6 +7,8 @@ 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) {
@@ -14,6 +16,8 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
@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(),
@@ -21,13 +25,24 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
});
}
async validate(payload: JwtPayload) {
async validate(payload: JwtPayload, req: any) {
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);
const cachedUser = await this.redis.get<any>(sessionKey);
if (cachedUser) {
// await this.auditAccess(cachedUser);
return cachedUser;
return {
id: cachedUser.id,
sellerId: cachedUser.sellerId,
storeId: cachedUser.storeId,
username: cachedUser.name,
email: cachedUser.email,
name: cachedUser.name,
};
}
const user = await this.userRepository.findById(payload.id);
@@ -35,13 +50,19 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
throw new UnauthorizedException('Usuário inválido ou inativo');
}
await this.redis.set(sessionKey, user, 60 * 60 * 8); // 8h
return {
const userData = {
id: user.id,
name: user.name,
sellerId: user.sellerId,
storeId: user.storeId,
username: user.name,
email: user.email,
name: user.name,
sessionId: payload.sessionId, // Inclui sessionId do token
};
await this.redis.set(sessionKey, userData, 60 * 60 * 8);
return userData;
}
private buildSessionKey(userId: number): string {