지금까지 API에 대한 Access Control은 JWT를 활용하여 사용자의 로그인 여부를 확인하는 것이었습니다. 그러나 보통 WebSite는 사용자에게 모든 API에 대한 권한을 부여하지 않고, User의 Type(관리자 혹은 방문자 등), 즉 Role에 대해 선택적으로 권한을 부여합니다. 이번엔 사용자의 Role에 따라 Access를 허용하는 Guard를 작성하고 Custom Decorator까지 만들어보도록 하겠습니다.
Authorization은 사용자가 수행할 수 있는 작업을 결정하는 Process를 나타냅니다. 예를 들어, Admin User는 게시물을 작성, 수정, 삭제할 수 있지만 Admin이 아닌 일반 사용자는 게시물의 조회만 가능합니다.
Authorization은 Authentication(인증)과 독립적이지만, 인증 메커니즘이 필요합니다. Authorization을 처리하기 위해 다양한 접근 방식과 전략이 존재하지만, NestJS에서 제공하는 Guard를 활용하여 기본적인 역할 기반 엑세스 제어(Role-Based Access Control) 메커니즘을 구현해보도록 하겠습니다.
RBAC Mechanism을 구현하기 위해서 먼저 사용자의 역할을 정의해줘야 합니다. 본 Project는 제품의 공급망 관리(Supply Chain Management) 시스템을 구축하는 것입니다. 따라서 이 시스템을 사용하는 User는 전체 System을 관리하는 Genuio
와 제품의 공급을 책임지고 조회하는 Manufacturer
로 구분됩니다.
userType
column을 생성하여 사용자의 역할을 추가합니다. 굳이 Enum은 사용하지 않고, comment
로 genuio
와 manufacturer
로 Type을 지정한다는 코멘트를 남깁니다.
이제 @Role
Decorator를 작성하여 route Handler
에 Custom Metadate를 붙이고, 특정 Route에 Access하기 위한 Role을 지정할 수 있게 해줍니다.AllowedRole
Type을 정의하고, SetMetadata
를 통해 roles
라는 metadata를 사용할 수 있는 기능을 제공합니다.
Route에 Access하기 위한 Role을 지정해줬으니, 이제 User에게 권한 부여를 할 수 있는지에 대한 Validation을 해주기 위해 RoleGuard
를 작성합니다.
roles
custom metadata에 접근한 후 AllowedRole
Type의 Data를 추출하여 requiredRoles
에 할당해줍니다.requiredRoles
가 존재하지 않을 것이므로 true
를 반환합니다.JwtGuard
를 통과한 후 request
객체에서 user
정보를 추출합니다.roles
가 Any
라면 누구나 Access 가능하다는 뜻이므로 true
를 반환합니다.userType
이 roles
에 포함되었는지 여부를 반환하여 검사합니다.이제 다음과 같이 Controller에서 RoleGuard
와 @Role
Decorator를 적용할 수 있습니다.
현재 Swagger, Guard 등 Decorator들이 너무 많아 직관적이지 않고 코드가 지저분해 보입니다. 따라서 Auth
에 필요한 Decorator를 한번에 묶어 제공해봅시다.
Role
, wtAuthGuard
, RoleGuard
3개의 데코레이터를 모두 묶어 나열하여 applyDecorators
로 적용합니다. 주의할 점은 RoleGuard
가 실행될 때 request
객체에 user
가 존재해야 하므로 JwtAuthGuard
가 먼저 실행되어야 한다는 점입니다. 조금 더 깔끔해진 Controller를 봅시다.