Welcome back, fellow developers! Today, we have an interesting topic to discuss: whether to use a global guard or different guards for route authorization. If you’re facing a situation where you have a global guard but need to exclude it for certain requests (like login or register), you’re in the right place. In this blog post, we’ll explore the best practices to resolve this predicament. Let’s dive right in!
Understanding the Routes: Before we proceed, let’s take a closer look at the routes we’re dealing with. We have a login route and an allUser route. The login route allows users to authenticate by providing their email and password. On the other hand, the allUser route is only accessible to users with the “admin” role. Both routes are crucial, but we need to handle them differently when it comes to authorization.
The AuthGuard Example: To address this challenge, we’ll leverage an AuthGuard. This guard will determine whether a request should be allowed or denied based on the user’s role and the route’s metadata. Let’s examine the AuthGuard implementation to understand how it works.
@Injectable() export class AuthGuard implements CanActivate { constructor(private reflector: Reflector) {} canActivate(context: ExecutionContext): boolean { const isPublic = this.reflector.getAllAndOverride<boolean>("public",[context.getHandler(),context.getClass()] ); const getHandler = this.reflector.get<string[] >('roles', context.getHandler()); if (isPublic) { return true; } const request = context.switchToHttp().getRequest(); const roles = request.user["roles"] ; if (roles === "guest" && typeof isPublic === "undefined") { return true; } else { throw new UnauthorizedException(); } } } As you can see, the AuthGuard checks for the presence of the "public" metadata on the route. If it's set to true, indicating that the route is public, the guard allows access without any further checks. However, if the metadata is not present or set to false, the guard verifies the user's role. If the user is a guest and the route doesn't specify any roles, access is granted. Otherwise, an UnauthorizedException is thrown.
Resolving the Exclusion for Login and Register: Now that we understand the AuthGuard’s functionality, let’s focus on excluding it for the login and register routes. These routes need to bypass the authorization check since they are responsible for authentication and user registration. Here’s how you can achieve that:
- For the login route, decorate the corresponding controller method with the
@SetMetadata('public', true)
decorator. This metadata informs the AuthGuard that the route is public and should not be subjected to authorization checks.
javascriptCopy code
@SetMetadata('public', true)
@Post('login')
public async login(
@Body('email') email: string,
@Body('password') password: string,
): Promise<any> {
return this.authService.loginUser(email, password);
}
- Similarly, for the register route, follow the same approach and decorate the appropriate controller method with the
@SetMetadata('public', true)
decorator.
By applying these decorators, you effectively exclude the login and register routes from the AuthGuard’s authorization process. Now, these routes will be accessible without any authentication or role checks.