[英]How to make guard optional only in particular case in NestJs?
我在 NestJS 中有以下两个守卫(一个用于基于 api 密钥的身份验证,另一个用于基于令牌的身份验证)。ApiKeyGuard 是重中之重。我想实现一个系统,如果有人有钥匙,它不会检查另一个守卫。在有 ApiKeyGuard 的情况下,有什么方法可以根据第一个 Guard 是否通过来使 AuthGuard 可选?
// Can be accessed with token within app as well as third party users
@UseGuards(ApiKeyGuard, AuthGuard)
@Get('/get-products')
async getProducts(): Promise<any> {
try {
return this.moduleRef
.get(`appService`, { strict: false })
.getProducts();
} catch (error) {
throw new InternalServerErrorException(error.message, error.status);
}
}
// Only to be accessed with token within app
@UseGuards(AuthGuard)
@Get('/get-users')
async getUsers(): Promise<any> {
try {
return this.moduleRef
.get(`appService`, { strict: false })
.getUsers();
} catch (error) {
throw new InternalServerErrorException(error.message, error.status);
}
}
下面的守卫用于检查基于 api 密钥的身份验证
api-key.guard.ts
@Injectable()
export class ApiKeyGuard implements CanActivate {
constructor(private readonly apiKeyService: ApiKeyService) {}
async canActivate(context: ExecutionContext): Promise<boolean> {
const req = context.switchToHttp().getRequest();
const key = req.headers['X-API-KEY'] ?? req.query.api_key;
return this.apiKeyService.isKeyValid(key);
}
下面的守卫用于检查基于令牌的身份验证
authentication.guard.ts
@Injectable()
export class AuthGuard implements CanActivate, OnModuleInit {
constructor(private readonly moduleRef: ModuleRef) {}
onModuleInit() {}
async canActivate(context: ExecutionContext): Promise<boolean> {
try {
// Get request data and validate token
const request = context.switchToHttp().getRequest();
if (request.headers.authorization) {
const token = request.headers.authorization.split(' ')[1];
const response = await this.checkToken(token);
if (response) {
return response;
} else {
throw new UnauthorizedException();
}
} else {
throw new UnauthorizedException();
}
} catch (error) {
throw new UnauthorizedException();
}
}
}
我所做的是使用@nestjs/passport并使用AuthGuard
并制定自定义 PassportJS 策略。 我有一个类似的问题,并寻找一种方法来完成这个而不使用一些“魔法”。 可以在此处找到文档。
在AuthGuard
中,您可以添加多个守卫。 它有点隐藏在文档中,尽管它非常强大。 看看这里,尤其是该部分的最后一行,它指出:
除了扩展默认的错误处理和认证逻辑外,我们还可以通过一系列策略允许对 go 进行认证。 第一个成功、重定向或错误的策略将停止链。 身份验证失败将依次通过每个策略,如果所有策略都失败,则最终失败。
可以这样做:
export class JwtAuthGuard extends AuthGuard(['strategy_jwt_1', 'strategy_jwt_2', '...']) { ... }
现在,回到您的示例,您必须创建 2 个自定义策略,一个用于 API 密钥,一个用于授权 header,这两个守卫都应该被激活。
所以对于 API 策略(例如):
import { Strategy } from 'passport-custom';
import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-custom';
import { Injectable, UnauthorizedException } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
@Injectable()
export class ApiStrategy extends PassportStrategy(Strategy, 'api-strategy') {
constructor(private readonly apiKeyService: ApiKeyService) {}
async validate(req: Request): Promise<User> {
const key = req.headers['X-API-KEY'] ?? req.query.api_key;
if ((await this.apiKeyService.isKeyValid(key)) === false) {
throw new UnauthorizedException();
}
return this.getUser();
}
}
为您的其他身份验证方式做类似的事情,然后按如下方式使用 Passport guard:
@UseGuard(AuthGuard(['api-strategy', 'other-strategy'])
这样,守卫将尝试所有策略(按顺序),当所有策略都失败时,您的身份验证失败。 如果其中之一成功,则您已通过身份验证!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.