| 123456789101112131415161718192021222324252627282930313233343536373839404142434445 |
- import { Injectable } from '@nestjs/common';
- import { PassportStrategy } from '@nestjs/passport';
- import { ExtractJwt, Strategy } from 'passport-jwt';
- import { ConfigService } from '@nestjs/config';
- import { UserService } from '../user/user.service';
- import { SafeUser } from '../user/dto/user-safe.dto'; // Import SafeUser
- @Injectable()
- export class JwtStrategy extends PassportStrategy(Strategy) {
- constructor(
- private configService: ConfigService,
- private userService: UserService,
- ) {
- super({
- jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(),
- ignoreExpiration: false,
- secretOrKey: configService.get<string>('JWT_SECRET')!,
- });
- }
- // Passport first verifies the JWT's signature and expiration, then calls this method.
- async validate(payload: {
- sub: string;
- username: string;
- role?: string;
- tenantId?: string;
- }): Promise<SafeUser | null> {
- // 1. ALWAYS lookup by ID (sub) for identity stability
- const user = await this.userService.findOneById(payload.sub);
- if (user) {
- // 2. ALWAYS prioritize database values for role/tenant to prevent stale token access
- return {
- id: user.id,
- username: user.username,
- role: user.role, // Use DB role
- tenantId: user.tenantId, // Use DB tenantId
- isAdmin: user.isAdmin,
- createdAt: user.createdAt,
- updatedAt: user.updatedAt,
- } as SafeUser;
- }
- return null;
- }
- }
|