如何使用类装饰器将装饰器应用于所有类方法

我正在使用实验性打字稿装饰器来管理 express 中的访问控制。


class AccountController extends Controller {

  

  login(req: Request, res: Response) {

    const { email, password } = req.body;

    const token = await this.model.login(email, password);

    return res.json({

      token

    });

  }


  @hasRole('ADMIN')

  list(req: Request, res: Response) {

    res.json({

      data: await this.model.findAll()

    });

  }

}


hasRole方法装饰器工作正常,我很满意。


Controller实现 REST 方法:


class Controller {

  list(req: Request, res: Response) { // impl }

  get(req: Request, res: Response) { // impl } 

  create(req: Request, res: Response) { // impl }

  update(req: Request, res: Response) { // impl }

  delete(req: Request, res: Response) { // impl }

}

问题是,我必须对大多数其他控制器应用相同的装饰器,而且我发现它非常重复。例如,StockController应该只允许访问MERCHANT角色,我必须执行如下操作:


class StockController extends Controller {

  @hasRole('MERCHANT')

  list(req: Request, res: Response) { 

    return super.list(req, res);

  }

  @hasRole('MERCHANT')

  get(req: Request, res: Response) { 

    return super.get(req, res);

  } 

  @hasRole('MERCHANT')

  create(req: Request, res: Response) { 

    return super.create(req, res);

  }

  @hasRole('MERCHANT')

  update(req: Request, res: Response) { 

    return super.update(req, res);

  }

  @hasRole('MERCHANT')

  delete(req: Request, res: Response) { 

    return super.delete(req, res);

  }

}

这种方法不仅乏味和重复而且不安全,因为如果我添加了一个方法Controller并且不小心忘记了将方法添加到子控制器,它们将允许不需要的访问。


我想用类装饰器处理这个问题并使用如下内容:


@requireRole('MERCHANT')

class StockController extends Controller {}

但是,根据我在文档中看到的内容:


类装饰器应用于类的构造函数,可用于观察、修改或替换类定义。


据我了解,我无法在类装饰器中实现“方法挂钩”。有什么建议么?


供您参考,hasRole装饰器如下所示:

export function hasRole(role: string) {

  return function(target: Object, propertyKey: string, descriptor: PropertyDescriptor) {

    const originalMethod = descriptor.value;

    descriptor.value = function(req: Request, res: Response) {

      const user = res.locals.user;

      if (user && user.hasRole(role)) {

        originalMethod.apply(this, [req, res]);

      } else {

        res.status(403).json({});

      }

    }

  }

}


繁星coding
浏览 112回答 1
1回答

萧十郎

这可以通过覆盖类方法来实现function AttachToAllClassDecorator<T>(someParam: string) {&nbsp; &nbsp; return function(target: new (...params: any[]) => T) {&nbsp; &nbsp; &nbsp; &nbsp; for (const key of Object.getOwnPropertyNames(target.prototype)) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // maybe blacklist methods here&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (descriptor) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; descriptor = someDecorator(someParam)(key, descriptor);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; Object.defineProperty(target.prototype, key, descriptor);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}基本上遍历所有方法(可能围绕它添加一些逻辑以将某些方法列入白名单/黑名单)并用包装了方法装饰器的新方法覆盖。这是方法装饰器的基本示例。function someDecorator(someParam: string): (methodName: string, descriptor: PropertyDescriptor) => PropertyDescriptor {&nbsp; &nbsp; return (methodName: string, descriptor: PropertyDescriptor): PropertyDescriptor => {&nbsp; &nbsp; &nbsp; &nbsp; let method = descriptor.value;&nbsp; &nbsp; &nbsp; &nbsp; descriptor.value = function(...args: any[]) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; console.warn(`Here for descriptor ${methodName} with param ${someParam}`);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return method.apply(this, args);&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return descriptor;&nbsp; &nbsp; }}TS游乐场
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

JavaScript