Files
gongxue-base/apps/server/src/auth/strategies/jwt.strategy.ts

65 lines
2.1 KiB
TypeScript

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<User>,
) {
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<string>();
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,
};
}
}