STLEON
@STLEON
In Console We Trust. Code hard. Or die.

Как get_current_user() выполнять асинхронно в Tornado?

В чем проблема.

Во время вызова get_current_user() в Торнадо нужно выполнить некоторые асинхронные запросы.

Попытки сделать get_current_user() асинхронным не увенчались успехом, поэтому было принято решение написать свой велосипед.

def authenticated_async(method):

    @gen.coroutine
    def wrapper(self, *args, **kwargs):
        self._auto_finish = False
        self.current_user = yield gen.Task(self.get_current_user_async)
        if not self.current_user:
            self.redirect(self.reverse_url('login'))
        else:
            result = method(self, *args, **kwargs)
            if result is not None:
                yield result
    return wrapper

class BaseClass():

    @gen.coroutine
    def get_current_user_async(self,):
        auth_cookie = self.get_secure_cookie('user')
        user_id = yield gen.Task(c.hget, 'auths', auth_cookie)
        print(123, user_id)
        return auth_cookie if auth_cookie else None


В примере используется Redis, откуда берем значение из hash.

Проблема в том, что когда использую декоратор @authenticated_async, то в консоли должен быть вывод не только одинокого 123. Пример:

class IndexPageHandler(BaseClass, RequestHandler):

    @authenticated_async
    def get(self):
        self.render("index.html")


В чем проблема, почему user_id пуст и как это исправить?

Может, кто-то уже делал метод get_current_user() асинхронным, поделитесь реализацией.

Спасибо!
  • Вопрос задан
  • 678 просмотров
Решения вопроса 1
STLEON
@STLEON Автор вопроса
In Console We Trust. Code hard. Or die.
Код правильный, за исключением

auth_cookie = self.get_secure_cookie('user')

Так как используется Python 3, tornado-redis ожидает юникодные строчки, а не байтовые.

Таким образом, он обработает не юникодную строку str().

Поэтому надо юзать:

auth_cookie = tornado.escape.native_str(self.get_secure_cookie('user'))
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@mooody
class BaseHandler(RequestHandler):
    async def get_current_user_async(self):
        session_hash = self.get_secure_cookie("session_hash")
        return session_hash

def authenticated_async(method):
    @functools.wraps(method)
    async def wrapper(self, *args, **kwargs):
        if not await self.get_current_user_async():
            if self.request.method in ("GET", "HEAD"):
                url = self.get_login_url()
                if "?" not in url:
                    if urlparse.urlsplit(url).scheme:
                        # if login url is absolute, make next absolute too
                        next_url = self.request.full_url()
                    else:
                        next_url = self.request.uri
                    url += "?" + urlencode(dict(expired=next_url))
                self.redirect(url)
                return
            raise HTTPError(403)
        return await method(self, *args, **kwargs)
    return wrapper
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы