使用带有异步回调的 cookie 密钥进行身份验证

发布于 2024-09-01 15:36:20 字数 1876 浏览 6 评论 0原文

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

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

第二个问题。在异步获取 API url 期间,用户页面在 on_response 设置 cookie 之前已加载,并且该页面将包含未经授权的部分,其中包含用于登录或登录的链接。这会让用户感到困惑。为了解决这个问题,我可以停止为尝试加载网站首页的用户加载页面。是否可以做以及如何做?也许这个问题有更正确的方法来解决?

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

I need to write authentication function with asynchronous callback from remote Auth API. Simple authentication with login is working well, but authorization with cookie key, does not work. It should checks if in cookies present key "lp_login", fetch API url like async and execute on_response function.

The code almost works, but I see two problems. First, in on_response function I need to setup secure cookie for authorized user on every page. In code user_id returns correct ID, but line: self.set_secure_cookie("user", user_id) does't work. Why it can be?

And second problem. During async fetch API url, user's page has loaded before on_response setup cookie with key "user" and the page will has an unauthorized section with link to login or sign on. It will be confusing for users. To solve it, I can stop loading page for user who trying to load first page of site. Is it possible to do and how? Maybe the problem has more correct way to solve it?

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

莫相离 2024-09-08 15:36:20

您似乎在此处

您遇到的问题之一是您无法在 get_current_user 内部启动异步调用,只能从 get 内部发生的事情启动异步调用> 或发布

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

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

It seems you cross-posted this on the tornado mailing list here

One of the problems you are running into is that you can't start the async call inside of get_current_user, you can only start an async call from something that happens inside of get or post.

I've not tested it, but i think this should get you close to what you are looking for.

#!/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')
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文