|
1 | | -import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; |
| 1 | +import { |
| 2 | + CanActivate, |
| 3 | + ExecutionContext, |
| 4 | + Inject, |
| 5 | + Injectable, |
| 6 | +} from '@nestjs/common'; |
| 7 | +import { FastifyRequest } from 'fastify'; |
| 8 | +import { JwtService } from '../../infrastructure/jwt/jwt.service'; |
| 9 | +import { Reflector } from '@nestjs/core'; |
| 10 | +import { AUTH_ROLES_KEY, JWT_AUTH_SERVICE } from '../../auth.tokens'; |
| 11 | +import { isNone, none, Option, some } from 'effect/Option'; |
| 12 | +import { QueryBus } from '@nestjs/cqrs'; |
| 13 | +import { CheckAuthUserByIdQuery } from '../../application/query/check-auth-user-by-id.query'; |
| 14 | +import { IS_PUBLIC_API } from '../../../../libs/decorator/auth.decorator'; |
| 15 | +import { ApiRole } from '../../../../libs/api/api-role.enum'; |
2 | 16 |
|
3 | 17 | @Injectable() |
4 | 18 | export class AuthGuard implements CanActivate { |
5 | | - constructor() {} |
| 19 | + private authenticationHeaders: string[] = ['Authorization', 'authorization']; |
| 20 | + |
| 21 | + constructor( |
| 22 | + private readonly reflector: Reflector, |
| 23 | + @Inject(JWT_AUTH_SERVICE) |
| 24 | + private readonly jwtService: JwtService, |
| 25 | + private readonly queryBus: QueryBus, |
| 26 | + ) {} |
6 | 27 |
|
7 | 28 | async canActivate(context: ExecutionContext): Promise<boolean> { |
8 | | - console.log(context); |
9 | | - return true; |
| 29 | + const apiRoles = this.reflector.getAllAndOverride<ApiRole[]>( |
| 30 | + AUTH_ROLES_KEY, |
| 31 | + [context.getHandler(), context.getClass()], |
| 32 | + ); |
| 33 | + const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_API, [ |
| 34 | + context.getHandler(), |
| 35 | + context.getClass(), |
| 36 | + ]); |
| 37 | + if (isPublic && !apiRoles) return true; |
| 38 | + const request = context.switchToHttp().getRequest<FastifyRequest>(); |
| 39 | + const token = this.extractToken(request); |
| 40 | + if (isNone(token)) return false; |
| 41 | + try { |
| 42 | + const authUser = await this.jwtService.verifyToken(token.value); |
| 43 | + if (isNone(authUser)) return false; |
| 44 | + request['user'] = authUser.value; |
| 45 | + const isActiveUser = await this.isActiveUser(authUser.value.id); |
| 46 | + return isActiveUser && apiRoles.includes(authUser.value.role); |
| 47 | + } catch { |
| 48 | + return false; |
| 49 | + } |
| 50 | + } |
| 51 | + |
| 52 | + private extractToken(request: FastifyRequest): Option<string> { |
| 53 | + for (const header of this.authenticationHeaders) { |
| 54 | + const tokenHeader = request.headers[header] as string; |
| 55 | + if (tokenHeader) { |
| 56 | + const splitted = tokenHeader.split(' '); |
| 57 | + if (splitted[0] !== 'Bearer') { |
| 58 | + return none(); |
| 59 | + } else { |
| 60 | + return some(splitted[1]); |
| 61 | + } |
| 62 | + } |
| 63 | + } |
| 64 | + return none(); |
| 65 | + } |
| 66 | + |
| 67 | + private async isActiveUser(userId: string): Promise<boolean> { |
| 68 | + return await this.queryBus.execute(new CheckAuthUserByIdQuery(userId)); |
10 | 69 | } |
11 | 70 | } |
0 commit comments