0

我正试图绕过龙卷风。我正在编写一个由 mongodb 支持的聊天应用程序,我正在使用motor它进行非阻塞访问。

我想要实现的是:

  1. 创建一个装饰器,用于motor从 mongo 异步拉取用户的记录
  2. 验证他们的凭据(用户名和令牌)
  3. 创建另一个装饰器,检查上面 1. 中检索到的 user_id 是否被允许访问聊天室。这需要另一个异步调用 mongomotor来检索“ChatRoom”记录。
  4. 如果一切正常,请订阅聊天室

我有装饰器 1. 工作(基本上取自http://tornadogists.org/5251927/):

def authenticated_async(f):
    @functools.wraps(f)
    @gen.engine
    def wrapper(self, *args, **kwargs):
        self.current_user = yield gen.Task(self.get_current_user_async)
        if self.current_user:
            logging.info("User '%s' (%s) successfully authenticated" %
                         (self.current_user['username'],
                          self.current_user['_id']))
            f(self, *args, **kwargs)
        else:
            raise tornado.web.HTTPError(401, "User not authenticated, "
                                             "aborting")
    return wrapper

麻烦的是,对于第二个装饰器,我需要访问self.current_user. 因为这是在异步回调中设置的,所以当我进入我validation的装饰器时它不可用(即在 auth 装饰器完成之前调用验证装饰器)。

我不可能以这种方式将装饰器与异步函数一起使用吗?在确保它self.current_user是 True 之后,我是否只需要在上述方法中调用验证方法,这样它更像是一个回调?

理想情况下,我希望在我的 Handler 中使用这两个装饰器包装我的方法,以便我可以在其他地方重用它们,即:

class ChatSocketHandler(tornado.websocket.WebSocketHandler):
    @gen.coroutine
    @validate_invitation_access_async
    @authenticated_async
    def open(self, invitation_id):
        # do stuff here...

更新 其实没有依赖。user_id 作为参数提供,可用于并行运行两个装饰器 - 一个用于确认身份验证,另一个用于查看是否允许具有该 ID 的用户访问房间。只有在 时,该open()方法才会继续self.auth_check == True and self.room_check == True

可以open()在异步装饰器完成之前调用吗?

4

1 回答 1

0

您需要切换装饰器的顺序,以便您的validate_invitation_access_async包装器可以访问 current_user:

@authenticated_async
@validate_invitation_access_async
def open(self, invitation_id):
        # do stuff here...

然后里面的包装器validate_invitation_access_async是 "f" in authenticated_async: 它在 self.current_user 设置后调用。请注意,您不需要额外的gen.engine装饰器,所有包装器都已经是引擎。你的包装可能是这样的:

def validate_invitation_access_async(f):
    @gen.engine
    def wrapper(self, *args, **kwargs):
        # ... use Motor to see if user is authorized ...
        # if not, log and redirect. otherwise:
        f(self, *args, **kwargs)

您还应该更新您的代码以使用 Tornado 3 的 gen.coroutine 而不是 gen.engine:它更干净。但我把它留作练习。

于 2014-03-10T16:00:33.417 回答