Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add exclude feature for useGlobalGuards #964

Closed
weeco opened this issue Aug 12, 2018 · 7 comments
Closed

Add exclude feature for useGlobalGuards #964

weeco opened this issue Aug 12, 2018 · 7 comments

Comments

@weeco
Copy link

weeco commented Aug 12, 2018

Similiar to the exclude feature for middleware I am hereby requesting an exclude feature for the useGlobalGuards method. I believe one can use the same arguments as used in the middleware exclude feature request issue (#790), to argue why this feature is helpful.

Use case:

While I am using a generally JWT protected API, I'd like to have an unprotected health and metrics endpoint so that it can be scraped by Kubernetes and Prometheus. Therefore I would like to exclude these two controllers.

@kamilmysliwiec
Copy link
Member

Honestly, it's almost impossible to port this feature to Nest. The execution context, global injectables like guards, interceptors, they are held separately, regardless of application's type. We cannot differentiate them by path, that would require a lot of design changes.

@weeco
Copy link
Author

weeco commented Aug 16, 2018

@kamilmysliwiec Alright, do you have a suggestion to handle my the problem in the described use case with NestJS though?

@kamilmysliwiec
Copy link
Member

I'm guessing that the only available solutions are: a) use different binding scope (one by one tie guard to the controllers/methods), b) add if statement directly in the guard (for example, extend AuthGuard pick request from ExecutionContext and compare request path)

@jwhitmarsh
Copy link

@weeco how did you end up accomplishing this? Any recommendations?

@rhogeranacleto
Copy link

I am also looking for a smart solution for this situation. 🙁

@bintzandt
Copy link

bintzandt commented Apr 8, 2019

What we ended up doing was to create a global guard (in this case the AuthGuard) which looks like this:

import { CanActivate, ExecutionContext, Injectable } from "@nestjs/common";
import { Reflector } from "@nestjs/core";

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

	public canActivate( context: ExecutionContext ): boolean {
		const isPublic = this.reflector.get<boolean>( "isPublic", context.getHandler() );

		if ( isPublic ) {
			return true;
		}

		// Make sure to check the authorization, for now, just return false to have a difference between public routes.
		return false;
	}
}

This guard is then added globally to all the routes using the following in main.ts:

const reflector = app.get( Reflector );
app.useGlobalGuards( new AuthGuard( reflector ) );

Exclusions to this guard can be made by using a decorator. We named it Public() which looks like this:

import { SetMetadata } from "@nestjs/common";

export const Public = () => SetMetadata( "isPublic", true );

Now authentication is required for all the routes and exclusions for a specific route or class can be made by adding the @Public() decorator. For example:

@Public()
@Get()
public getHello(): string {
   return this.appService.getHello();
}

Of course you have to add your own authentication to the auth.guard.ts to make sure that it returns true whenever someone is authorised to visit the route (probably if req.user is set...).

@lock
Copy link

lock bot commented Sep 23, 2019

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

@lock lock bot locked as resolved and limited conversation to collaborators Sep 23, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants