【问题标题】:Authentication using cookie key with asynchronous callback使用带有异步回调的 cookie 密钥进行身份验证
【发布时间】:2010-05-17 12:16:49
【问题描述】:

我需要使用远程身份验证 API 的异步回调编写身份验证函数。使用登录的简单身份验证运行良好,但使用 cookie 密钥的授权不起作用。它应该检查 cookie 中是否存在密钥“lp_login”,像异步一样获取 API url 并执行 on_response 函数。

代码几乎可以工作,但我发现了两个问题。首先,在 on_response 函数中,我需要在每个页面上为授权用户设置安全 cookie。在代码中 user_id 返回正确的 ID,但 line: self.set_secure_cookie("user", user_id) 不起作用。为什么会这样?

第二个问题。在异步获取 API url 期间,用户的页面在 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

【问题讨论】:

    标签: python authentication asynchronous tornado


    【解决方案1】:

    您似乎在 tornado 邮件列表 here 上交叉发布了此内容

    您遇到的一个问题是您无法在get_current_user 内部启动异步调用,您只能从getpost 内部发生的事情开始异步调用。

    我没有测试过,但我认为这应该可以让你接近你正在寻找的东西。

    #!/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')
    

    【讨论】:

      猜你喜欢
      • 2015-12-07
      • 2012-02-04
      • 1970-01-01
      • 2012-11-11
      • 2020-02-21
      • 2012-08-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多