简体   繁体   English

如何在Tornado RequestHandler中存储数据库会话

[英]How to store database session in Tornado RequestHandler

I'm implementing a secure cookie scheme for user session management in Tornado. 我正在Tornado中实现用于用户会话管理的安全cookie方案。 The user's details are accessed via SQLAlchemy. 用户的详细信息可通过SQLAlchemy访问。 Currently I need to open two database sessions: one to verify that a user exists during authentication, and another to query other parts of the model. 当前,我需要打开两个数据库会话:一个用于验证用户在身份验证期间是否存在,另一个用于查询模型的其他部分。 Something like this: 像这样:

class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user_id = self.get_secure_cookie('user')
        if not user_id:
            return None
        with model.session_scope() as session:
            user = session.query(model.AppUser).get(user_id)
            if not user:
                return None
            session.expunge(user)
        return user

class OtherHandler(BaseHandler):
    @tornado.web.authenticated
    @gen.coroutine
    def put(self, ob_id):
        with model.session_scope() as session:
             other = session.query(model.Other).get(ob_id)
             session.merge(self.current_user)
             if not user.can_view(other):
                 raise AuthzError
             yield self.some_operation(other)
        self.finish()

It would be nice if I didn't have to use merge to bring the user object back into the session. 如果我不必使用merge将用户对象带回到会话中,那就太好了。 Is there a safe way to store the database session and persistent user object in the handler? 有没有安全的方法将数据库会话和持久性 user对象存储在处理程序中? I'm considering doing something like this: 我正在考虑做这样的事情:

class BaseHandler(tornado.web.RequestHandler):
    def prepare(self):
        self.session = model.Session()
        user_id = self.get_secure_cookie('user')
        if user_id:
            self.current_user = session.query(model.AppUser).get(user_id)

    def finish(self, chunk=None):
        try:
            return super().finish(chunk)
        finally:
            self.session.commit()

    def send_error(self, status_code=500, **kwargs):
        try:
            return super().send_error(status_code=status_code, **kwargs)
        finally:
            self.session.rollback()

Questions: 问题:

  1. Is it safe to store the session (or anything else) in self , even when using async code ( @gen.coroutine and yield )? 它是安全的存储session (或其他任何东西)在self使用异步代码(时,即使@gen.coroutineyield )?
  2. Is the way I'm closing the session in finish and send_error robust ? 我在finishsend_error关闭会话的方式是否可靠 I want to make sure I don't have any zombie sessions hanging around. 我想确保我没有任何僵尸会议。

Is the way I'm closing the session in finish and send_error robust? 我在finish和send_error中关闭会话的方式是否可靠? I want to make sure I don't have any zombie sessions hanging around 我想确保我没有任何僵尸会议

You can use either on_finish or on_connection_close . 您可以使用on_finishon_connection_close

def on_finish(self):
    if self.get_status_code() >= 500:
        self.session.rollback()
    else:
        self.session.commit()

Note that may exist a better way to distinguish an error response. 请注意,可能存在区分错误响应的更好方法。 Also take a look at the discussion - https://github.com/tornadoweb/tornado/issues/517 还可以看看讨论-https: //github.com/tornadoweb/tornado/issues/517

Is it safe to store the session (or anything else) in self, even when using async code (@gen.coroutine and yield)? 即使使用异步代码(@ gen.coroutine和yield),将会话(或其他任何内容)自身存储起来是否安全?

The RequestHandler object is created for every request, it's not shared. 为每个请求创建RequestHandler对象,但不共享该对象。 Asynchronous in that context, does not make the code more vulnerable (I think) to store data in " self ". 在这种情况下,异步不会使代码更容易(我认为)将数据存储在“ self ”中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM