Authentifizierung mit Cookie Schlüsseln mit asynchronem Callback
-
27-09-2019 - |
Frage
Ich brauche Authentifizierungsfunktion mit asynchronem Rückruf von Remote-Auth-API zu schreiben. Einfache Authentifizierung mit Login funktioniert gut, aber Genehmigung mit Cookie-Taste funktioniert nicht. Es sollte überprüft, ob in Cookies vorhanden Schlüssel "lp_login", API URL wie async holen und ausführen on_response Funktion.
Der Code fast funktioniert, aber ich sehe zwei Probleme. Zuerst in on_response Funktion muss ich Setup sicheres Cookie für autorisierte Benutzer auf jeder Seite. In Code user_id gibt korrekte ID, aber Zeile: self.set_secure_cookie ( "user", user_id) does't Arbeit. Warum kann es sein?
Und zweites Problem. Während Asynchron-API-URL holen, Seite des Benutzers vor on_response Setup-Cookie geladen mit der Taste „Benutzer“ und die Seite hat einen nicht autorisierten Abschnitt mit Link zur Anmeldung oder anmelden. Es wird verwirrend für die Nutzer sein. Um es zu lösen, kann ich Laden Seite für den Benutzer stoppen, die erste Seite der Website zu laden versuchen. Ist es möglich, zu tun und wie? Vielleicht ist das Problem hat richtigere Weg, es zu lösen?
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
Lösung
Es scheint, dass Sie dies auf der Tornado-Mailingliste Cross-Gepostet hier
Eines der Probleme, die Sie in laufen ist, dass Sie nicht von dem Asynchron-Anruf innerhalb von get_current_user
starten können, können Sie nur einen Asynchron-Anruf von etwas beginnen, das innerhalb von get
oder post
passiert.
Ich habe es nicht getestet, aber ich denke, das sollte Sie in der Nähe bekommen, was Sie suchen.
#!/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')