jwt.strategy.ts 1.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445
  1. import { Injectable } from '@nestjs/common';
  2. import { PassportStrategy } from '@nestjs/passport';
  3. import { ExtractJwt, Strategy } from 'passport-jwt';
  4. import { ConfigService } from '@nestjs/config';
  5. import { UserService } from '../user/user.service';
  6. import { SafeUser } from '../user/dto/user-safe.dto'; // Import SafeUser
  7. @Injectable()
  8. export class JwtStrategy extends PassportStrategy(Strategy) {
  9. constructor(
  10. private configService: ConfigService,
  11. private userService: UserService,
  12. ) {
  13. super({
  14. jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
  15. ignoreExpiration: false,
  16. secretOrKey: configService.get<string>('JWT_SECRET')!,
  17. });
  18. }
  19. // Passport first verifies the JWT's signature and expiration, then calls this method.
  20. async validate(payload: {
  21. sub: string;
  22. username: string;
  23. role?: string;
  24. tenantId?: string;
  25. }): Promise<SafeUser | null> {
  26. // 1. ALWAYS lookup by ID (sub) for identity stability
  27. const user = await this.userService.findOneById(payload.sub);
  28. if (user) {
  29. // 2. ALWAYS prioritize database values for role/tenant to prevent stale token access
  30. return {
  31. id: user.id,
  32. username: user.username,
  33. role: user.role, // Use DB role
  34. tenantId: user.tenantId, // Use DB tenantId
  35. isAdmin: user.isAdmin,
  36. createdAt: user.createdAt,
  37. updatedAt: user.updatedAt,
  38. } as SafeUser;
  39. }
  40. return null;
  41. }
  42. }