使用具有异步回调的cookie密钥进行身份验证
问题描述:
我需要使用来自远程Auth API的异步回调来编写身份验证功能。使用登录进行简单身份验证运行良好,但使用Cookie密钥进行身份验证不起作用。它应该检查cookie中是否存在关键字“lp_login”,获取像异步一样的API url并执行on_response函数。使用具有异步回调的cookie密钥进行身份验证
该代码几乎可行,但我看到两个问题。首先,在on_response函数中,我需要为每个页面上的授权用户设置安全cookie。在代码中user_id返回正确的ID,但行:self.set_secure_cookie(“用户”,user_id)不起作用。为什么会这样?
第二个问题。在异步抓取API网址期间,用户的页面已经在on_response设置cookie之前加载了关键字为“user”的页面,并且该页面将有一个未授权的部分,其中包含登录或登录链接。这会让用户感到困惑。为了解决这个问题,我可以停止为试图加载网站第一页的用户加载页面。是否有可能做到如何?也许问题有更正确的解决方法?
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
答
看来你跨张贴这龙卷风邮件列表上here
一个你碰到的问题是,你不能启动的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')