전체 코드 : https://github.com/jeounpar/nestjs-jwt-roleguard-tutorial
1. role-guard.decorator.ts 파일 생성
import { SetMetadata } from '@nestjs/common';
export const Roles = (...roles: string[]) => SetMetadata('roles', roles);
@Role() 데코레이터로 사용된다.
2.auth.guard.ts 파일 수정
import {
CanActivate,
ExecutionContext,
Injectable,
UnauthorizedException,
} from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
@Injectable()
export class AuthGuard implements CanActivate {
constructor(private jwtService: JwtService, private reflector: Reflector) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const request = context.switchToHttp().getRequest();
const token = this.extractTokenFromHeader(request);
const handler = context.getHandler();
const apiRoles: string[] = this.reflector.get<string[]>('roles', handler);
if (!token) {
throw new UnauthorizedException();
}
try {
const payload = await this.jwtService.verifyAsync(token, {
secret: process.env.JWT_SECRET,
});
if (!apiRoles.includes(payload.role)) {
throw new UnauthorizedException();
}
} catch {
throw new UnauthorizedException();
}
return true;
}
private extractTokenFromHeader(request: Request): string | undefined {
const [type, token] = request.headers.authorization?.split(' ') ?? [];
return type === 'Bearer' ? token : undefined;
}
}
Reflector
NestJS에서 사용되는 리플렉션(reflection)을 지원하는 유틸리티 클래스이다. 리플렉션은 실행 중인 코드의 구조, 타입 및 어노테이션과 같은 메타데이터에 대한 정보를 검사하고 조작할 수 있는 능력을 말한다. Reflector 클래스는 이러한 리플렉션 작업을 간단하게 수행할 수 있도록 도우며, 주로 NestJS의 가드(Guard), 인터셉터(Interceptor), 필터(Filter), 파이프(Pipe) 등에서 활용된다.
ex) 어노테이션 추출, 메타데이터 조회, 메서드/프로퍼티 파라미터 타입 조회 등등
3.auth.service.ts 파일 수정
...
async login(id: string, password: string) {
const payload = {
id: id,
password: password,
role: 'user',
};
const accessToken = await this.jwtService.signAsync(payload);
return accessToken;
}
...
payload에 role을 부여한다. (모든 클라이언트는 user 역할을 부여 받는다)
4. app.controller.ts 및 app.service.ts 파일 수정
// app.controller.ts
import { Controller, Get, UseGuards } from '@nestjs/common';
import { AppService } from './app.service';
import { AuthGuard } from './auth/auth.guard';
import { Roles } from './decorator/role-guard.decorator';
@UseGuards(AuthGuard)
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@Roles('user')
@Get('user')
getUser(): string {
return this.appService.getUser();
}
@Roles('admin')
@Get('admin')
getAdmin(): string {
return this.appService.getAdmin();
}
}
import { Injectable } from '@nestjs/common';
@Injectable()
export class AppService {
getUser(): string {
return 'User!';
}
getAdmin(): string {
return 'Admin!';
}
}
GET /user API는 Role이 user만 호출 가능
GET /admin API는 Role이 admin만 호출 가능
4. RoleGuard 테스트
Role은 enum 클래스를 선언해서 사용하는 것이 좋아보인다.
요걸 잘 활용하면 OAuth 인증에도 사용 가능!
'개발 > Nest.js' 카테고리의 다른 글
01) Nest.js JWT인증 + RoleGuard 가이드 (0) | 2023.06.09 |
---|---|
Nest.js serverless + AWS Lambda 배포하기 (0) | 2023.03.19 |
Nest.js interface 구현체에 DI 적용하기 (0) | 2023.03.13 |