들어가며

NesJS는 데코레이터를 적극적으로 활용하여 코드를 간결하고 효율적으로 만드는 프레임워크이다. NestJS는 @Controller, @Get, @Post 등 다양한 내장 데코레이터를 제공하지만, 필요에 따라 커스텀 데코레이터를 생성하여 사용할 수도 있다. 여기에서는 NestJS에서 커스텀 데코레이터를 생성하여 API 접근을 제어하는 방법에 대해서 살펴본다. 특히, 특정 권한을 가진 사용자만 특정 API에 접근할 수 있도록 제어하는 데코레이터를 만들고 적용하는 과정을 다룬다.

커스텀 데코레이터: @Permission 생성하기

API 접근 권한을 나타내는 @Permission 데코레이터를 생성해보자. 이 데코레이터는 특정 권한(예: read, write, admin)을 메타데이터로 저장하여, 나중에 가드에서 해당 메타데이터를 확인하고 접근을 제어할 수 있도록 한다.

1
2
3
4
import { SetMetadata } from "@nestjs/common";

export const Permission = (permission: string) =>
SetMetadata("permission", permission);

이 코드에서 SetMetadata 함수는 NestJS에서 제공하는 유틸리티 함수로, 지정된 키와 값으로 메타데이터를 설정한다. Permission 데코레이터는 permission 문자열을 인자로 받아 ‘permission’이라는 키와 함께 메타데이터를 설정한다.

가드를 이용한 접근 제어: PermissionGuard

@Permission 데코레이터에서 설정한 메타데이터를 사용하여 실제로 API 접근을 제어하는 가드를 만들어야 한다. PermissionGuard는 canActivate 메서드를 통해 요청이 들어올 때마다 사용자의 권한을 확인하고, API에 접근할 수 있는지 여부를 결정한다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
import { Injectable, CanActivate, ExecutionContext } from "@nestjs/common";
import { Reflector } from "@nestjs/core";

@Injectable()
export class PermissionGuard implements CanActivate {
constructor(private reflector: Reflector) {}

canActivate(context: ExecutionContext): boolean {
// @Permission 데코레이터에서 설정된 permission 메타데이터 가져오기
const requiredPermission = this.reflector.get<string>(
"permission",
context.getHandler()
);

// requiredPermission이 없다면 모든 사용자 접근 허용
if (!requiredPermission) {
return true;
}

// 실제 애플리케이션에서는 DB 또는 세션에서 사용자 권한을 가져와야 합니다.
// 여기서는 예시로 userPermissions 배열을 사용합니다.
const userPermissions = ["read", "write"];

// 사용자 권한에 requiredPermission이 포함되어 있는지 확인
return userPermissions.includes(requiredPermission);
}
}

Reflector는 데코레이터에서 설정한 메타데이터를 가져오는 데 사용된다. context.getHandler() 는 현재 실행 중인 핸들러(컨트롤러 메서드)를 가져오고, this.reflector.get<string>('permission', context.getHandler()) 는 해당 핸들러에 설정된 ‘permssion’ 메타데이터를 가져온다.

컨트롤러에서 @Permission 데코레이터 적용하기

이제 @Permission 데코레이터와 PermissionGuard를 이용하여 특정 API에 접근 제어를 적용해보자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import { Controller, Get, UseGuards } from "@nestjs/common";
import { Permission } from "./permission.decorator";
import { PermissionGuard } from "./permission.guard";

@Controller("data")
@UseGuards(PermissionGuard) // 컨트롤러 레벨에서 PermissionGuard 적용
export class DataController {
@Get("public")
getPublicData() {
return "Public data";
}

@Get("protected")
@Permission("read") // read 권한 필요
getProtectedData() {
return "Protected data";
}
}

@UseGuards(PermissionGuard) 데코레이터는 DataController의 모든 메서드에 PermissionGuard를 적용한다. getPublicData() 메서드는 @Permission 데코레이터가 없으므로 모든 사용자가 접근할 수 있다. 반면에 getProtectedData() 메서드는 @Permission(‘read’) 데코레이터가 적용되어 있으므로, read 권한을 가진 사용자만 접근할 수 있다.

마무리

커스텀 데코레이터와 가드를 이용하면 NestJS에서 API 접근 제어를 유연하고 효율적으로 구현할 수 있다. 예제를 잘 활용하여 필요에 맞는 커스텀 데코레이터르 ㄹ만들고 적용하여 애플리케이션의 보안과 기능을 향상시킬 수 있기를 기대한다.

예제 코드

nestjs-custom-deco