Nx NestJs Angular Guard

agnusdei·2023년 7월 5일
0
post-custom-banner
npx nx generate @nx/nest:guard admin-role --project=server --directory=guards --language=ts --no-interactive


1. 가드 생성

2. 일반적인 가드와 데코레이터 폴더 경로 Server Side

import {
  CanActivate,
  ExecutionContext,
  HttpException,
  Injectable,
  UnauthorizedException,
  Logger,
} from '@nestjs/common';
import { PrismaService } from '../../../prisma/prisma.service';
import { AuthUtil } from '../auth-util.service';
import { AccessTokenType } from '@namdorang/interface';

@Injectable()
export class AuthGuard implements CanActivate {
  constructor(
    private readonly authUtil: AuthUtil,
    private readonly prismaService: PrismaService
  ) {}

  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest(); // Http 요청을 중간에 가로 채기
    // 인증 정보 확인을 위해 변수에 할당
    const header = request.headers;
    const authorization = header.authorization; // authoriztion 이 없음!! 왜?

    // 국제 표준 형식 : Authorization: <type> <credentials>
    if (!authorization) {
      throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
    }
    // <type> 타입 이름 => Bearer
    if (!authorization.startsWith('Bearer ')) {
      throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
    }
    // <credentials> => random string
    const token = authorization.split(' ')[1];
    if (!token) {
      throw new UnauthorizedException('사용자 정보를 찾을 수 없습니다.');
    }

    let id;

    try {
      const payload = this.authUtil.verifyToken<AccessTokenType>(token);
      if (!payload.id) {
        throw new UnauthorizedException('유효하지 않은 토큰입니다.');
      }
      id = payload.id;
    } catch (e) {
      throw new HttpException('사용할 수 없는 토큰입니다.', 498);
    }

	// await
    const admin = await this.prismaService.admin.findUnique({ where: { id } });
    if (!admin) {
      throw new UnauthorizedException('유효하지 않은 토큰입니다.');
    }

    request.user = admin; // http header 에 인증 정보를 담기

    return true;
  }
}
  1. auth.graud.ts 파일 내부 구조 : 상세한 설명은 주석을 참고해 주세요.
import {
  CanActivate,
  ExecutionContext,
  Injectable,
  Logger,
  UnauthorizedException,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { AdminRole } from '@prisma/client';

@Injectable()
// 가드 사용 시 CanActivate 구현
export class AdminRoleGuard implements CanActivate {
  constructor(private readonly reflector: Reflector) {} // Reflector 메타 데이터 회수

  // ExecutionContext: 현재 실행되는 프로세스의 다양한 정보를 가져올 수 있는 새로운 helper method들을 가지고 있음
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const required = this.reflector.getAllAndOverride<string[]>('admin_roles', [
      context.getHandler(),
      context.getClass(),
    ]);
    Logger.log('admin-role.guard start');

    const request = context.switchToHttp().getRequest();
    Logger.log(request.user);
    const user = request.user;
    Logger.log(user.username);
    const roles: AdminRole[] = (await user)?.roles;

    const intersections = roles?.filter((role) => required.includes(role));

    if (!intersections || intersections?.length < 1) {
      throw new UnauthorizedException('사용 권한이 없습니다.');
    }
    Logger.log('admin-role.guard end');
    return true;
  }
}
  1. admin-role.guard.ts 파일 내부 : 상세 설명은 주석에~
  2. 테코레이터 폴더 생성 및 admin 과 auth 를 둘 다 연결할 데코레이터 ts 파일을 생성합니다.
import {
  Logger,
  SetMetadata,
  UseGuards,
  applyDecorators,
} from '@nestjs/common';
import { AdminRole } from '@prisma/client';
import { AuthGuard } from '../guards/auth.guard';
import { AdminRoleGuard } from '../guards/admin-role.guard';

/**해당 코드는 NestJS에서 사용되는 커스텀 데코레이터인 AdminAuth를 정의하는 함수입니다.
 * 이 데코레이터는 관리자 권한을 가진 사용자만 접근할 수 있는 엔드포인트를 보호하는 데 사용됩니다.
 */
export function AdminAuth(...roles: AdminRole[]) {
  Logger.debug('fwaffwafwfwafwafwafwafw');
  return applyDecorators(
    /**SetMetadata는 NestJS에서 메타데이터를 설정하기 위한 함수입니다.
     * 여기서는 'admin_roles'라는 키로 roles 값을 설정합니다.
     * 이를 통해 해당 엔드포인트에 필요한 관리자 역할을 지정할 수 있습니다. */
    SetMetadata('admin_roles', roles),
    /**
     * UseGuards는 NestJS에서 가드를 사용하기 위한 함수입니다.
     * 가드는 엔드포인트에 접근하기 전에 실행되는 미들웨어로, 특정 조건을 확인하여 접근을 허용하거나 거부합니다.
     * 이 코드에서는 AuthGuard와 AdminRoleGuard 가드를 사용합니다.
     */
    UseGuards(AuthGuard, AdminRoleGuard)
  );
}
  1. admin-auth.decoratoe.ts 내부: 이제 두 가드를 동시에 사용합니다.

  2. auth.contorller.ts 파일 내부 인증 오퍼레이션에

@AdminAuth(AdminRole.NORMAL, AdminRole.SUPER)

로 선언하여 사용할 수 있습니다.

post-custom-banner

0개의 댓글