L'authentification en utilisant la clé de cookie avec rappel asynchrone
-
27-09-2019 - |
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
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')