我有一个问题。
是否可以在一条路线上使用多个身份验证防护(在我的情况下是基本身份验证和 ldap 身份验证)。当一名守卫成功时,应验证该路线。
Ber*_*rtC 24
如果您查看 AuthGuard,您会看到以下定义:
(文件是node_modules/@nestjs/passport/dist/auth.guard.d.ts)
export declare const AuthGuard: (type?: string | string[]) => Type<IAuthGuard>;
Run Code Online (Sandbox Code Playgroud)
这意味着 AuthGuard 可以接收字符串数组。
在我的代码中,我执行了以下操作:
@UseGuards(AuthGuard(["jwt", "api-key"]))
@Get()
getOrders() {
return this.orderService.getAllOrders();
}
Run Code Online (Sandbox Code Playgroud)
在 Postman 中,端点可以拥有 api-key 和 JWT。
这意味着 2 个守卫之间存在 OR 函数。
tho*_*aux 17
简短的回答:不,如果您在一条路线上添加多个守卫,他们都需要通过该路线才能激活。
长答案:但是,通过让您的 LDAP 防护扩展基本防护,您想要完成的任务是可能的。如果 LDAP 特定逻辑成功,则返回true,否则返回调用结果super.canActivate()。然后,在您的控制器中,将基本或 LDAP 防护添加到您的路由中,但不能同时添加两者。
export BasicGuard implements CanActivate {
constructor(
protected readonly reflector: Reflector
) {}
async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
if () {
// Do some logic and return true if access is granted
return true;
}
return false;
}
}
Run Code Online (Sandbox Code Playgroud)
export LdapGuard extends BasicGuard implements CanActivate {
constructor(
protected readonly reflector: Reflector
) {
super(reflector);
}
async canActivate(context: ExecutionContext) {
const request = context.switchToHttp().getRequest();
if () {
// Do some logic and return true if access is granted
return true;
}
// Basically if this guard is false then try the super.canActivate. If its true then it would have returned already
return await super.canActivate(context);
}
}
Run Code Online (Sandbox Code Playgroud)
有关更多信息,请参阅官方 NestJS 存储库上的 GitHub 问题。
您可以创建一个抽象守卫,并在其中传递实例或引用,如果任何传递的守卫返回 true,则从此守卫返回 true。
假设您有 2 个守卫:BasicGuard和LdapGuard。UserController并且你有一个带有route的控制器@Get(),它应该受到这些守卫的保护。
因此,我们可以MultipleAuthorizeGuard使用下面的代码创建一个抽象守卫:
@Injectable()
export class MultipleAuthorizeGuard implements CanActivate {
constructor(private readonly reflector: Reflector, private readonly moduleRef: ModuleRef) {}
public canActivate(context: ExecutionContext): Observable<boolean> {
const allowedGuards = this.reflector.get<Type<CanActivate>[]>('multipleGuardsReferences', context.getHandler()) || [];
const guards = allowedGuards.map((guardReference) => this.moduleRef.get<CanActivate>(guardReference));
if (guards.length === 0) {
return of(true);
}
if (guards.length === 1) {
return guards[0].canActivate(context) as Observable<boolean>;
}
const checks$: Observable<boolean>[] = guards.map((guard) =>
(guard.canActivate(context) as Observable<boolean>).pipe(
catchError((err) => {
if (err instanceof UnauthorizedException) {
return of(false);
}
throw err;
}),
),
);
return forkJoin(checks$).pipe(map((results: boolean[]) => any(identity, results)));
}
}
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,该守卫不包含对特定守卫的任何引用,而仅接受引用列表。在我的示例中,所有守卫都返回Observable,因此我用来forkJoin运行多个请求。当然,它也可以应用于 Promise。
为了避免MultipleAuthorizeGuard在控制器中启动并手动传递必要的依赖项,我将此任务留给 Nest.js 并通过自定义装饰器传递引用MultipleGuardsReferences
export const MultipleGuardsReferences = (...guards: Type<CanActivate>[]) =>
SetMetadata('multipleGuardsReferences', guards);
Run Code Online (Sandbox Code Playgroud)
所以,在控制器中我们可以有下面的代码:
@Get()
@MultipleGuardsReferences(BasicGuard, LdapGuard)
@UseGuards(MultipleAuthorizeGuard)
public getUser(): Observable<User> {
return this.userService.getUser();
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3014 次 |
| 最近记录: |