GOOGLE ADS

miércoles, 20 de abril de 2022

NestJS: combine varios guardias y actívelos si uno devuelve verdadero

Tengo una pregunta.

¿Es posible usar múltiples guardias de autenticación en una ruta (en mi caso, autenticación básica y ldap). La ruta debe ser autenticada cuando un guardia fue exitoso.


Solución del problema

Puede crear una protección abstracta y pasar instancias o referencias allí, y devolver verdadero desde esta protección si alguna de las protecciones aprobadas devolvió verdadero.

Imaginemos que tienes 2 guardias: BasicGuardy LdapGuard. Y tienes un controlador UserControllercon ruta @Get(), que debe ser protegido por estos guardias.

Entonces, podemos crear una guardia abstracta MultipleAuthorizeGuardcon el siguiente código:

@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)));
}
}

Como puede ver, este guardia no contiene ninguna referencia a un guardia en particular, sino que solo acepta la lista de referencias. En mi ejemplo, todos los guardias regresan Observable, por lo que uso forkJoinpara ejecutar múltiples solicitudes. Pero, por supuesto, también se puede adoptar para Promises.

Para evitar iniciar MultipleAuthorizeGuarden el controlador y pasar las dependencias necesarias manualmente, le dejo esta tarea a Nest.js y paso las referencias a través de un decorador personalizado.MultipleGuardsReferences

export const MultipleGuardsReferences = (...guards: Type<CanActivate>[]) =>
SetMetadata('multipleGuardsReferences', guards);

Entonces, en el controlador podemos tener el siguiente código:

@Get()
@MultipleGuardsReferences(BasicGuard, LdapGuard)
@UseGuards(MultipleAuthorizeGuard)
public getUser(): Observable<User> {
return this.userService.getUser();
}

No hay comentarios:

Publicar un comentario

Regla de Firestore para acceder a la generación de subcolección Permisos faltantes o insuficientes

Tengo problemas con las reglas de Firestore para permitir el acceso a algunos recursos en una subcolección. Tengo algunos requests document...