es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Existe alguna forma de acceder a los argumentos del método controlador en un guardia de NestJS?

Quiero implementar un guardia inteligente en NestJS que pueda proteger la ejecución de métodos basándose en decisiones declaradas en una anotación especial del método.

Por ejemplo, el caso de uso es el siguiente:

Los usuarios normales solo pueden cambiar su propia información de usuario.

El administrador puede cambiar cualquier información de usuario.

Quiero especificar las decisiones de manera declarativa, utilizando anotaciones. Casi he completado la implementación, este requisito puede declararse de la siguiente manera:

@Put(‘user’)
@UseGuards(HttpBasicAuthGuard, DecisionGuard)
@DecisionExpr(new Decisions(Op.OR, [
new RootDecision(Role.ADMIN),
new CurrentUserDecision({ sourceParamId: ‘user’, func: (user: User) => user.id}),
]))
updateUser(@ParamId(‘user’) @Body() u: User, @ParamId(‘etc’) etc): any {
// llamar al servicio de usuarios y actualizar el modelo de usuario
}

Las decisiones declaradas se almacenan en la metadata del método controlador mediante ‘@DecisionExpr’.

Los índices de los parámetros se recopilan mediante ‘@ParamId’ y también se almacenan en la metadata del método controlador.

Las decisiones son evaluadas por DecisionGuard, que puede acceder al usuario actual y a las autoridades desde la solicitud (a través del ExecutionContext), y también puede acceder fácilmente a las decisiones y a los índices de parámetros identificados desde la metadata.

El único problema es cómo puedo acceder a los argumentos del método controlador desde DecisionGuard. Los argumentos del método controlador contienen datos que se pueden comparar con el usuario actual y tomar una decisión para DecisionGuard.

¿Es posible en absoluto?

La única forma que encontré fue implementar un decorador de método y llamar a un método personalizado cambiando PropertyDescriptor.value (tercer argumento del decorador de método):

export const DecisionExpr = (data: Decision): MethodDecorator => {

const childFunction = descriptor.value;
descriptor.value = (…args: any[]) => {
console.log(‘Función secundaria de DecisionExpr – args:’, args);
// llamar al método original
return childFunction.apply(this, args);
};
}

Pero el problema con esta solución es que el método personalizado solo se llama DESPUÉS de los guardias.

Mi última oportunidad es mover esta protección de DecisionGuard al método personalizado del decorador de método DecisionExpr, pero no me gusta. No quiero introducir un nuevo patrón para la protección de métodos.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    Implementando un Smart Guard en NestJS utilizando la Anotación de Métodos

    Como experto en IT especializado en anotaciones, NestJS y decoradores, puedo sugerir la siguiente solución para implementar un Smart Guard en NestJS, que puede proteger la ejecución del método en base a decisiones declaradas en una anotación especial de método:

    El primer paso es declarar los requisitos utilizando anotaciones. Esto se puede hacer utilizando el decorador ‘@DecisionExpr’ para definir las decisiones específicas requeridas para el método. Por ejemplo, si los usuarios normales solo pueden cambiar su propia información de usuario y los administradores pueden cambiar cualquier información de usuario, utiliza el siguiente código:

    @Put('user')
    @UseGuards(HttpBasicAuthGuard, DecisionGuard)
    @DecisionExpr(new Decisions(Op.OR, [
      new RootDecision(Role.ADMIN),
      new CurrentUserDecision({ sourceParamId: 'user', func: (user: User) => user.id }),
    ]))
    updateUser(@ParamId('user') @Body() u: User, @ParamId('etc') etc): any {
      // llama al servicio de usuario y actualiza al usuario en el modelo
    }
    

    En este código, las decisiones se declaran en metadatos de un método controlador utilizando el decorador ‘@DecisionExpr’. Los índices de los parámetros se recolectan utilizando ‘@ParamId’ y también se almacenan en los metadatos del método controlador.

    A continuación, se evalúan las decisiones utilizando un DecisionGuard, que puede acceder al usuario actual y a las autoridades desde la solicitud (a través de ExecutionContext), y las decisiones e índices de parámetros identificados de los metadatos.

    El único problema que surge es cómo acceder a los argumentos del método controlador desde DecisionGuard. Los argumentos del método controlador contienen datos que se pueden comparar con el usuario actual y tomar una decisión para DecisionGuard.

    Una solución es implementar un decorador de método y llamar a un método personalizado cambiando PropertyDescriptor.value, de la siguiente manera:

    export const DecisionExpr = (data: Decision): MethodDecorator => {
        ...
        const childFunction = descriptor.value;
        descriptor.value = (...args: any[]) => {
          console.log('DecisionExpr child function - args:', args);
          // llama al método original
          return childFunction.apply(this, args);
        };
    }
    

    Pero esto solo llama al método personalizado DESPUÉS de los guards, lo cual no es ideal.

    Una mejor solución sería mover esta protección desde DecisionGuard hacia el método personalizado del decorador ‘@DecisionExpr’ en el método. Esto no solo proporcionará una mejor estructura, sino que también evitará introducir un nuevo patrón de protección de método.

    Siguiendo estos pasos, puedes implementar con éxito un Smart Guard en NestJS que puede proteger la ejecución del método en base a decisiones.

Comments are closed.