Node.js/Nest

Guards

WebDevLee 2023. 11. 21. 15:31

Nest.js의 Guards에 대해 정리하였습니다.



< Guards >

Guards have a single responsibility. They determine whether a given request will be handled by the route handler or not, depending on certain conditions (like permissions, roles, ACLs, etc.) present at run-time. This is often referred to as authorization.

A guard is a class annotated with the @Injectable( ) decorator, which implements the CanActivate interface.

 

< HINT >
Guards are executed after all middleware, but before any interceptor or pipe.

 

 


< Authorization guard >

It will extract and validate the token, and use the extracted information to determine whether the request can proceed or not.

 

Ex : auth.guard.ts

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Observable } from 'rxjs';

@Injectable()
export class AuthGuard implements CanActivate {
  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {
    const request = context.switchToHttp().getRequest();
    return validateRequest(request);
  }
}

Every guard must implement a canActivate( ) function. This function should return a boolean, indicating whether the current request is allowed or not. It can return the response either synchronously or asynchronously (via a Promise or Observable). Nest uses the return value to control the next action:

  • if it returns  true , the request will be processed.
  • if it returns  false , Nest will deny the request.

 

 


< Binding guard >

Like pipes and exception filters, guards can be controller-scoped, method-scoped, or global-scoped.

 

Controllr-scoped

@Controller('cats')
@UseGuards(RolesGuard)
export class CatsController {}

 

Global-scoped

const app = await NestFactory.create(AppModule);
app.useGlobalGuards(new RolesGuard());
import { Module } from '@nestjs/common';
import { APP_GUARD } from '@nestjs/core';

@Module({
  providers: [
    {
      provide: APP_GUARD,
      useClass: RolesGuard,
    },
  ],
})
export class AppModule {}

 

 


< Setting roles per handler >

Nest provides the ability to attach custom metadata to route handlers through either decorators created via Reflector#createDecorator static method, or the built-in @SetMetadata( ) decorator.

 

Ex)

import { Reflector } from '@nestjs/core';

export const Roles = Reflector.createDecorator<string[]>();

: The Roles decorator here is a function that takes a single argument of type string[].

@Post()
@Roles(['admin'])
async create(@Body() createCatDto: CreateCatDto) {
  this.catsService.create(createCatDto);
}

Here we've attached the Roles decorator metadata to the create() method, indicating that only users with the admin role should be allowed to access this route.

 

 


< Example >

import { Injectable, CanActivate, ExecutionContext } from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Roles } from './roles.decorator';

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

  canActivate(context: ExecutionContext): boolean {
    const roles = this.reflector.get(Roles, context.getHandler());
    if (!roles) {
      return true;
    }
    const request = context.switchToHttp().getRequest();
    const user = request.user;
    return matchRoles(roles, user.roles);
  }
}

 

 


Reference : https://docs.nestjs.com/guards

 

Documentation | NestJS - A progressive Node.js framework

Nest is a framework for building efficient, scalable Node.js server-side applications. It uses progressive JavaScript, is built with TypeScript and combines elements of OOP (Object Oriented Programming), FP (Functional Programming), and FRP (Functional Rea

docs.nestjs.com