为了账号安全,请及时绑定邮箱和手机立即绑定

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

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

繁星coding 2022-12-29 14:13:27
我正在使用实验性打字稿装饰器来管理 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({});      }    }  }}
查看完整描述

1 回答

?
萧十郎

TA贡献1815条经验 获得超13个赞

这可以通过覆盖类方法来实现


function AttachToAllClassDecorator<T>(someParam: string) {

    return function(target: new (...params: any[]) => T) {

        for (const key of Object.getOwnPropertyNames(target.prototype)) {

            // maybe blacklist methods here

            let descriptor = Object.getOwnPropertyDescriptor(target.prototype, key);

            if (descriptor) {

                descriptor = someDecorator(someParam)(key, descriptor);

                Object.defineProperty(target.prototype, key, descriptor);

            }

        }

    }

}

基本上遍历所有方法(可能围绕它添加一些逻辑以将某些方法列入白名单/黑名单)并用包装了方法装饰器的新方法覆盖。


这是方法装饰器的基本示例。


function someDecorator(someParam: string): (methodName: string, descriptor: PropertyDescriptor) => PropertyDescriptor {

    return (methodName: string, descriptor: PropertyDescriptor): PropertyDescriptor => {

        let method = descriptor.value;


        descriptor.value = function(...args: any[]) {

            console.warn(`Here for descriptor ${methodName} with param ${someParam}`);


            return method.apply(this, args);

        }


        return descriptor;

    }

}

TS游乐场


查看完整回答
反对 回复 2022-12-29
  • 1 回答
  • 0 关注
  • 111 浏览
慕课专栏
更多

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信