Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to override global scoped guard with controller/method scoped one

Tags:

nestjs

I'm writing webAPI using NestJS framework. I was not able to override global scoped guard with the one placed on method or controller level. All of my endpoints will use JWT verification guard except one used for logging into the system. Is it possible to create one guard on root level and only override this global guard with @UseGuard() decorator on single method level?

I tried to use guard before listen function call and also use APP_GUARDprovider, but in both cases I'm not able to override this behavior.

Code example: https://codesandbox.io/embed/nest-yymkf

like image 939
Maciek Przybylski Avatar asked Jul 19 '19 17:07

Maciek Przybylski


1 Answers

Just to add my 2 cents.

Instead of defining 2 guards (reject and accept) as the OP have done, I have defined a custom decorator:

import { SetMetadata } from '@nestjs/common'

export const NoAuth = () => SetMetadata('no-auth', true)

The reject guard (AuthGuard) uses Reflector to be able to access the decorator's metadata and decides to activate or not based on it.

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

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

  canActivate(
    context: ExecutionContext,
  ): boolean | Promise<boolean> | Observable<boolean> {

    const noAuth = this.reflector.get<boolean>('no-auth', context.getHandler())

    if(noAuth) return true

    // else your logic here
  }
}

I then bind the reject guard globally in some module:

@Module({
  providers: [{
    provide: APP_GUARD,
    useClass: AuthGuard
  }]
})

and proceed to use the decorator where needed:

@NoAuth()
@Get() // anyone can access this
getHello(): string {
  return 'Hello Stranger!'
}

@Get('secret') // protected by the global guard
getSecret(): string {
  return 'ssshhh!' 
}
like image 65
Johnny Avatar answered Sep 23 '22 23:09

Johnny