# 认证与守卫 ## JWT 策略 ```typescript // jwt.strategy.ts import { Injectable } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; import { ConfigService } from '@nestjs/config'; @Injectable() export class JwtStrategy extends PassportStrategy(Strategy) { constructor(private config: ConfigService) { super({ jwtFromRequest: ExtractJwt.fromAuthHeaderAsBearerToken(), ignoreExpiration: false, secretOrKey: config.get('JWT_SECRET'), }); } async validate(payload: { sub: string; email: string; role: string }) { return { userId: payload.sub, email: payload.email, role: payload.role }; } } ``` ## JWT 认证守卫 ```typescript // jwt-auth.guard.ts import { Injectable, ExecutionContext, UnauthorizedException } from '@nestjs/common'; import { AuthGuard } from '@nestjs/passport'; import { Reflector } from '@nestjs/core'; @Injectable() export class JwtAuthGuard extends AuthGuard('jwt') { constructor(private reflector: Reflector) { super(); } canActivate(context: ExecutionContext) { const isPublic = this.reflector.get('isPublic', context.getHandler()); if (isPublic) return true; return super.canActivate(context); } handleRequest(err: any, user: any) { if (err || !user) { throw err || new UnauthorizedException('无效的令牌'); } return user; } } // 公开装饰器 export const Public = () => SetMetadata('isPublic', true); ``` ## 角色守卫 ```typescript // roles.decorator.ts export const Roles = (...roles: string[]) => SetMetadata('roles', roles); // roles.guard.ts @Injectable() export class RolesGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const roles = this.reflector.getAllAndOverride('roles', [ context.getHandler(), context.getClass(), ]); if (!roles) return true; const { user } = context.switchToHttp().getRequest(); return roles.includes(user.role); } } // 用法 @UseGuards(JwtAuthGuard, RolesGuard) @Roles('admin') @Get('admin') adminEndpoint() {} ``` ## 认证服务 ```typescript @Injectable() export class AuthService { constructor( private usersService: UsersService, private jwtService: JwtService, ) {} async validateUser(email: string, password: string): Promise { const user = await this.usersService.findByEmail(email); if (user && await bcrypt.compare(password, user.password)) { return user; } return null; } async login(user: User) { const payload = { sub: user.id, email: user.email, role: user.role }; return { access_token: this.jwtService.sign(payload), refresh_token: this.jwtService.sign(payload, { expiresIn: '7d' }), }; } async register(dto: CreateUserDto) { const hashedPassword = await bcrypt.hash(dto.password, 10); return this.usersService.create({ ...dto, password: hashedPassword }); } } ``` ## 认证模块配置 ```typescript @Module({ imports: [ PassportModule.register({ defaultStrategy: 'jwt' }), JwtModule.registerAsync({ inject: [ConfigService], useFactory: (config: ConfigService) => ({ secret: config.get('JWT_SECRET'), signOptions: { expiresIn: '15m' }, }), }), UsersModule, ], providers: [AuthService, JwtStrategy], exports: [AuthService], }) export class AuthModule {} ``` ## 全局应用守卫 ```typescript // app.module.ts @Module({ providers: [ { provide: APP_GUARD, useClass: JwtAuthGuard }, { provide: APP_GUARD, useClass: RolesGuard }, ], }) export class AppModule {} ``` ## 快速参考 | 组件 | 用途 | |-----------|---------| | `JwtStrategy` | 验证 JWT 令牌 | | `JwtAuthGuard` | 保护路由 | | `RolesGuard` | 基于角色的访问控制 | | `@Public()` | 跳过认证 | | `@Roles('admin')` | 要求角色 | | `@UseGuards()` | 应用守卫 |