Аутентификация с использованием ключа cookie с асинхронным обратным вызовом - PullRequest
0 голосов
/ 17 мая 2010

Мне нужно написать функцию аутентификации с асинхронным обратным вызовом из удаленного API авторизации. Простая аутентификация с логином работает хорошо, но авторизация с ключом cookie, не работает. Он должен проверить, присутствует ли в файлах cookie ключ "lp_login", получить URL-адрес API, например async, и выполнить функцию on_response.

Код почти работает, но я вижу две проблемы. Во-первых, в функции on_response мне нужно установить безопасный cookie для авторизованного пользователя на каждой странице. В коде user_id возвращает правильный идентификатор, но строка: self.set_secure_cookie ("user", user_id) не работает. Почему это может быть?

И вторая проблема. Во время URL-адреса API асинхронной выборки страница пользователя загружается перед установочным файлом cookie on_response с ключом «пользователь», и на странице будет неавторизованный раздел со ссылкой для входа или входа. Это будет сбивать с толку пользователей. Чтобы решить эту проблему, я могу остановить загрузку страницы для пользователя, который пытается загрузить первую страницу сайта. Можно ли это сделать и как? Может быть, проблема имеет более правильный способ ее решения?

class BaseHandler(tornado.web.RequestHandler):
    @tornado.web.asynchronous
    def get_current_user(self):
        user_id = self.get_secure_cookie("user")
        user_cookie = self.get_cookie("lp_login")
        if user_id:
            self.set_secure_cookie("user", user_id)
            return Author.objects.get(id=int(user_id))
        elif user_cookie:
            url = urlparse("http://%s" % self.request.host)
            domain = url.netloc.split(":")[0]
            try:
                username, hashed_password = urllib.unquote(user_cookie).rsplit(',',1)
            except ValueError:
                # check against malicious clients
                return None
            else:
                url = "http://%s%s%s/%s/" % (domain, "/api/user/username/", username, hashed_password)
                http = tornado.httpclient.AsyncHTTPClient()
                http.fetch(url, callback=self.async_callback(self.on_response))
        else:
            return None

    def on_response(self, response):
        answer = tornado.escape.json_decode(response.body)
        username = answer['username']
        if answer["has_valid_credentials"]:
            author = Author.objects.get(email=answer["email"])
            user_id = str(author.id)
            print user_id # It returns needed id
            self.set_secure_cookie("user", user_id) # but session can's setup

1 Ответ

3 голосов
/ 28 мая 2010

Кажется, вы добавили это в список рассылки торнадо здесь

Одна из проблем, с которыми вы сталкиваетесь, заключается в том, что вы не можете запустить асинхронный вызов внутри get_current_user, вы можете запустить асинхронный вызов только с того, что происходит внутри get или post.

Я не проверял это, но я думаю, что это должно приблизить вас к тому, что вы ищете.

#!/bin/python
import tornado.web
import tornado.http
import tornado.escape
import functools
import logging
import urllib

import Author

def upgrade_lp_login_cookie(method):
    @functools.wraps(method)
    def wrapper(self, *args, **kwargs):
        if not self.current_user and self.get_cookie('lp_login'):
            self.upgrade_lp_login(self.async_callback(method, self, *args, **kwargs))
        else:
            return method(self, *args, **kwargs)
    return wrapper


class BaseHandler(tornado.web.RequestHandler):
    def get_current_user(self):
        user_id = self.get_secure_cookie("user")
        if user_id:
            return Author.objects.get(id=int(user_id))

    def upgrade_lp_login(self, callback):
        lp_login = self.get_cookie("lp_login")
        try:
            username, hashed_password = urllib.unquote(lp_login).rsplit(',',1)
        except ValueError:
            # check against malicious clients
            logging.info('invalid lp_login cookie %s' % lp_login)
            return callback()

        url = "http://%(host)s/api/user/username/%s/%s" % (self.request.host, 
                                                        urllib.quote(username), 
                                                        urllib.quote(hashed_password))
        http = tornado.httpclient.AsyncHTTPClient()
        http.fetch(url, self.async_callback(self.finish_upgrade_lp_login, callback))

    def finish_upgrade_lp_login(self, callback, response):
        answer = tornado.escape.json_decode(response.body)
        # username = answer['username']
        if answer['has_valid_credentials']:
            # set for self.current_user, overriding previous output of self.get_current_user()
            self._current_user = Author.objects.get(email=answer["email"])
            # set the cookie for next request
            self.set_secure_cookie("user", str(self.current_user.id))

        # now chain to the real get/post method
        callback()

    @upgrade_lp_login_cookie
    def get(self):
        self.render('template.tmpl')
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...