【问题标题】:Async middleware in tornado龙卷风中的异步中间件
【发布时间】:2018-12-25 21:03:37
【问题描述】:

我的目标是在每个 websocket 请求初始化之前验证访问令牌。为此,我需要调用我的 oauth 服务器。所以试图添加一个中间件来检查访问令牌。我在这个链接https://github.com/tornadoweb/tornado/issues/49 中找到了如何添加中间件,效果很好。但问题是当我调用我的 oauth 服务器时,我是在异步进行的,而且看起来中间件不能是异步的。这是我的示例代码

app = Application()


async def middleware(request):
    userToken = request.headers.get('Authorization')
    active = await check_accesstoken(userToken)
    if not active:
      return error
    app(request)

async def check_accesstoken(userToken):
    http_client = httpclient.AsyncHTTPClient()
    post_data = {'token': userToken, 'scope': 'email phone'}
    api_endpoint = 'https://192.168.0.4:1445/oauth2/introspect'
    json_data = json.dumps(post_data)

    response = await http_client.fetch(api_endpoint,
                                       raise_error=False,
                                       method='POST',
                                       body=json_data
                                       # headers=headers
                                       )
    return response.body.active:


def main():    
    http_server = tornado.httpserver.HTTPServer(middleware)
    http_server.listen(PORT, HOST) 
    tornado.ioloop.IOLoop.current().start()

if __name__ == '__main__':
    main()

出现以下错误。

RuntimeWarning:从未等待协程“中间件”
self.request_callback(self.request)

问题

  1. 如何添加异步中间件?

  2. 或者我应该对 oauth 服务器进行同步调用吗?

  3. 或者还有其他地方我应该检查访问令牌吗?

【问题讨论】:

  • HTTPServer 类调用中间件就像一个同步函数。您必须通过继承来创建自己的服务器类,然后使用await 调用中间件。它可能有效,也可能无效,我还不确定。
  • 感谢您的回复。我明白你在说什么,但不知道该怎么做。如果我创建一个自定义服务器,那么它本身就可以像中间件一样工作。对?无法弄清楚如何在同步过程中挂钩异步方法。

标签: python tornado middleware


【解决方案1】:

是的,覆盖HTTPServer 麻烦多于值得。

想到的一个更明智的解决方案是,您可以将RequestHandler 子类化并在该子类上创建一个prepare() 方法,您可以在其中检查访问令牌。

然后从该子类创建所有处理程序。这是一个例子:

class BaseHandler(web.RequestHandler):
    async def prepare(self):
        active = await check_accesstoken(userToken)
        if not active:
            self.write("Error")
            self.finish()


class SomeHandler(BaseHandler):
    ...

如果您还需要在处理程序上创建prepare() 方法,只需使用super() 调用BaseHandlerprepare

【讨论】:

  • 我有 BaseHandler 类,它扩展了 tornado.websocket.WebSocketHandler。建立连接时会调用两个方法 init 和 on_message。 init 是同步的,所以不能在那里进行异步调用,并且 on_meesage 是异步的,我调用了 check_accesstoken 并且它工作正常。问题是在建立连接后可以多次调用 websocket on_message 但我不需要每次都检查访问令牌。如果我可以在 init 方法中检查访问令牌,那就太好了。无论如何,我想因为不支持异步中间件,所以我必须忍受它。
  • 解决方案中的另一件事是如何调用 prepare ?
  • @Aftab 对于 websockets,你应该在你的基类上创建一个 open() 方法。 prepare 代表RequestHandler,tornado 会自动调用它。
猜你喜欢
  • 1970-01-01
  • 2018-12-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多