62 lines
2.0 KiB
TypeScript
62 lines
2.0 KiB
TypeScript
import { ExtractJwt, Strategy } from 'passport-jwt';
|
|
import { PassportStrategy } from '@nestjs/passport';
|
|
import { Injectable, UnauthorizedException } from '@nestjs/common';
|
|
import { UsersService } from '../users/users.service';
|
|
import { getJwtSecret } from './auth.constants';
|
|
|
|
import { RedisService } from '../redis/redis.service';
|
|
import type { Request } from 'express';
|
|
|
|
export interface JwtPayload {
|
|
sub: string;
|
|
email?: string;
|
|
role?: string;
|
|
phoneNumber?: string;
|
|
}
|
|
|
|
@Injectable()
|
|
export class JwtStrategy extends PassportStrategy(Strategy) {
|
|
constructor(
|
|
private readonly usersService: UsersService,
|
|
private readonly redisService: RedisService,
|
|
) {
|
|
super({
|
|
jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
|
|
ignoreExpiration: false,
|
|
secretOrKey: getJwtSecret(),
|
|
passReqToCallback: true,
|
|
});
|
|
}
|
|
|
|
async validate(req: Request, payload: JwtPayload) {
|
|
const rawToken = ExtractJwt.fromAuthHeaderAsBearerToken()(req);
|
|
if (rawToken) {
|
|
const isBlacklisted = await this.redisService.get(`bl_token:${rawToken}`);
|
|
if (isBlacklisted) {
|
|
throw new UnauthorizedException('این توکن باطل شده است. لطفاً مجدداً وارد شوید');
|
|
}
|
|
}
|
|
// Handle fallback admin ID only in non-production environments if ADMIN_EMAIL matches
|
|
if (payload.sub === '12345678-1234-1234-1234-123456789012') {
|
|
if (process.env.NODE_ENV === 'production') {
|
|
throw new UnauthorizedException('حساب کاربری مدیریت معتبر نیست');
|
|
}
|
|
const adminEmail = process.env.ADMIN_EMAIL;
|
|
if (adminEmail && payload.email === adminEmail) {
|
|
return {
|
|
id: payload.sub,
|
|
email: adminEmail,
|
|
role: 'Admin',
|
|
};
|
|
}
|
|
throw new UnauthorizedException('حساب کاربری مدیریت معتبر نیست');
|
|
}
|
|
|
|
const user = await this.usersService.findById(payload.sub);
|
|
if (!user) {
|
|
throw new UnauthorizedException('کاربر یافت نشد');
|
|
}
|
|
return user;
|
|
}
|
|
}
|