import { Injectable, UnauthorizedException } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { ConfigService } from '@nestjs/config'; import { Request } from 'express'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { User } from '../../entities/user.entity'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor( config: ConfigService, @InjectRepository(User) private readonly userRepo: Repository, ) { super({ jwtFromRequest: ExtractJwt.fromExtractors([ // 1. Standard Bearer header (existing behavior) ExtractJwt.fromAuthHeaderAsBearerToken(), // 2. SSE fallback: query string ?token= (req: Request) => { const token = req?.query?.token; if (typeof token === 'string' && token.length > 0) { return token; } return null; }, ]), ignoreExpiration: false, secretOrKey: config.get('JWT_SECRET', 'dorm-billing-jwt-secret-key-2024'), }); } async validate(payload: { sub?: number; username?: string }) { if (!payload.sub) throw new UnauthorizedException('登录状态无效'); const user = await this.userRepo.findOne({ where: { id: payload.sub }, relations: ['roles', 'roles.permissions'], }); if (!user || !user.isActive || user.isArchived) { throw new UnauthorizedException('账号已失效,请重新登录'); } const permissions = new Set(); const roles: string[] = []; let isSuperAdmin = false; for (const role of user.roles ?? []) { if (role.status !== 1) continue; roles.push(role.name); if (role.name === '超管' || role.name === 'super_admin' || role.code === 'super_admin') { isSuperAdmin = true; } for (const permission of role.permissions ?? []) permissions.add(permission.code); } return { id: user.id, username: user.username, permissions: [...permissions], isSuperAdmin, roles, }; } }