Node.js

[NestJs]Guard 사용하기

무서운승태 2023. 12. 27. 16:17
728x90

Guard란??

  • pipe보다 먼저 실행된다.
  • request 객체를 가지고 여러 가지 처리를 가능하게 한다. 대표적으로 인증 처리를 한다.
  • 공식문서에 따르면 미들웨어보다 나은 방식으로 처리할 수 있다고 한다.
    • 미들웨어는 next()로 어떤 라우터가 실행될지 모르지만 guard는 ExcutionContext를 사용하기 때문에 어떠한 라우터가 실행될지 명확히 알 수 있다.
    • 코드가 명확해지고 DRY 하고 선언적으로 작성할 수 있다.

Guard 사용법

1. Guard로 사용할 class를 선언한다. CanActivate 인터페이스를 구현해야 한다.

@Injectable()
export class BearerTokenGuard implements CanActivate {
	async canActivate(context: ExecutionContext): Promise<boolean> {
    }
}

 

2. context객체를 이용하여 요청 데이터를 사용할 수 있다.

  • http 요청을 받을 것이기 때문에 switchToHttp를 사용하였다.
  • 다른 모듈의 service도 생성자로 포함시킬 수 있다.
@Injectable()
export class BearerTokenGuard implements CanActivate {
    constructor(
        private readonly authService: AuthService,
        private readonly usersService: UsersService,
    ) {}
    async canActivate(context: ExecutionContext): Promise<boolean> {
        const req = context.switchToHttp().getRequest();
    }
}

 

3. 토큰을 받아서 적절한 예외 처리 후 req 객체에 데이터를 넣는다.

  • req 객체에 데이터를 넣으면 이후 실행할 라우터에서 사용할 수 있다.
  • 정상적으로 인증처리가 완료되었으면 return true로 반환한다.
@Injectable()
export class BearerTokenGuard implements CanActivate {
    constructor(
        private readonly authService: AuthService,
        private readonly usersService: UsersService,
    ) {}
    async canActivate(context: ExecutionContext): Promise<boolean> {
        const req = context.switchToHttp().getRequest();
        const rowToken = req.headers['authorization'];

        if (!rowToken) {
            throw new UnauthorizedException('토큰이 없습니다.');
        }

        const token = this.authService.extractTokenFromHeader(rowToken, true);
        const result = await this.authService.verifyToken(token);
        const user = await this.usersService.getUserByEmail(result.email);

		// 이후 라우터에서 사용할수있다.
        req.user = user;
        req.token = token;
        req.tokenType = result.type;

        return true;
    }
}

 

4. 사용할 라우터에서 @UseGuards() 데코레이터를 사용한다.

  @Post('login/email')
    @UseGuards(BasicTokenGuard)
    async logEmail(@Headers('authorization') rowToken: string) {
        const token = this.authService.extractTokenFromHeader(rowToken, false);

        const credentials = this.authService.decodeBasicToken(token);

        return this.authService.logWithEmail(credentials);
    }