Question

Je dois écrire la fonction d'authentification avec rappel asynchrone de Auth API à distance. L'authentification simple avec connexion fonctionne bien, mais l'autorisation avec la clé des cookies, ne fonctionne pas. Il devrait vérifie si dans les cookies présents clé « lp_login », chercher url API comme async et exécuter on_response fonction.

Le code fonctionne presque, mais je vois deux problèmes. Tout d'abord, en fonction on_response je dois installer cookies sécurisé pour l'utilisateur autorisé sur chaque page. Dans le code user_id retourne ID correct, mais la ligne: self.set_secure_cookie ( "user", user_id) le travail de does't. Pourquoi il peut être?

Et deuxième problème. Au cours async chercher url API, la page de l'utilisateur a chargé avant cookie de configuration on_response avec la touche « utilisateur » et la volonté de la page a une section non autorisée lien pour vous connecter ou vous inscrire. Il sera source de confusion pour les utilisateurs. Pour le résoudre, je peux arrêter la page de chargement pour l'utilisateur qui essaie de charger la première page du site. Est-il possible de le faire et comment? Peut-être que le problème a de façon plus correcte pour le résoudre?

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
Était-ce utile?

La solution

Il vous semble permuté ce sur la liste de diffusion de tornade ici

L'un des problèmes que vous utilisez en est que vous ne pouvez pas lancer l'appel asynchrone à l'intérieur de get_current_user, vous ne pouvez démarrer un appel asynchrone de quelque chose qui se passe à l'intérieur de get ou post.

Je l'ai pas testé, mais je pense que cela devrait vous se rapprocher de ce que vous recherchez.

#!/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')
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top