| 1 | /* |
| 2 | * @Author: nevin |
| 3 | * @Date: 2024-12-22 21:14:15 |
| 4 | * @LastEditTime: 2025-02-25 21:33:04 |
| 5 | * @LastEditors: nevin |
| 6 | * @Description: |
| 7 | */ |
| 8 | import { |
| 9 | CanActivate, |
| 10 | createParamDecorator, |
| 11 | ExecutionContext, |
| 12 | Injectable, |
| 13 | UnauthorizedException, |
| 14 | } from '@nestjs/common'; |
| 15 | import { JwtService } from '@nestjs/jwt'; |
| 16 | import { Request } from 'express'; |
| 17 | import { SetMetadata } from '@nestjs/common'; |
| 18 | import { Reflector } from '@nestjs/core'; |
| 19 | |
| 20 | export const GetToken = createParamDecorator( |
| 21 | async (data: string, ctx: ExecutionContext) => { |
| 22 | const req = ctx.switchToHttp().getRequest(); |
| 23 | return req['user']; |
| 24 | }, |
| 25 | ); |
| 26 | |
| 27 | export const IS_PUBLIC_KEY = 'isPublic'; |
| 28 | export const Public = () => SetMetadata(IS_PUBLIC_KEY, true); |
| 29 | |
| 30 | @Injectable() |
| 31 | export class AuthGuard implements CanActivate { |
| 32 | constructor( |
| 33 | private jwtService: JwtService, |
| 34 | private reflector: Reflector, |
| 35 | ) {} |
| 36 | |
| 37 | async canActivate(context: ExecutionContext): Promise<boolean> { |
| 38 | const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [ |
| 39 | context.getHandler(), |
| 40 | context.getClass(), |
| 41 | ]); |
| 42 | if (isPublic) { |
| 43 | // 💡 查看此条件 |
| 44 | return true; |
| 45 | } |
| 46 | |
| 47 | const request = context.switchToHttp().getRequest(); |
| 48 | const token = this.extractTokenFromHeader(request); |
| 49 | if (!token) { |
| 50 | throw new UnauthorizedException(); |
| 51 | } |
| 52 | try { |
| 53 | const payload = await this.jwtService.verifyAsync(token, { |
| 54 | secret: process.env.AUTH_SECRET, |
| 55 | }); |
| 56 | // 以便我们可以在路由处理器中访问它 |
| 57 | request['user'] = payload; |
| 58 | } catch { |
| 59 | throw new UnauthorizedException(); |
| 60 | } |
| 61 | return true; |
| 62 | } |
| 63 | |
| 64 | private extractTokenFromHeader(request: Request): string | undefined { |
| 65 | const [type, token] = request.headers.authorization?.split(' ') ?? []; |
| 66 | return type === 'Bearer' ? token : undefined; |
| 67 | } |
| 68 | } |
| 69 |