tornado安全应用之用户认证

在这个例子中,我们将只通过存储在安全cookie里的用户名标识一个人。当某人首次在某个浏览器(或cookie过期后)访问我们的页面时,我们展示一个登录表单页面。表单作为到LoginHandler路由的POST请求被提交。post方法的主体调用set_secure_cookie()来存储username请求参数中提交的值。

代码如下:

class BaseHandler(tornado.web.RequestHandler):

    def get_current_user(self):

        return self.get_secure_cookie("username")

class LoginHandler(BaseHandler):

    def get(self, *args, **kwargs):

        self.render('login.html')

    def post(self, *args, **kwargs):

        self.set_secure_cookie("username",self.get_argument("username"))

class WelcomeHandler(BaseHandler):

    @tornado.web.authenticated

    def get(self, *args, **kwargs):

        self.render('index.html',user=self.current_user)

class LogoutHandler(BaseHandler):

    def get(self, *args, **kwargs):

        if (self.get_argument("logout",None)):

            self.clear_cookie("username")

            self.redirect('/')

def server_function():

    cookie='bZJc2sWbQLKos6GkHn/VB9oXwQt8S0R0kRvJ5/xJ89E='

    tornado.options.parse_command_line()

    app = tornado.web.Application(handlers=[(r"/", WelcomeHandler),(r"/login",LoginHandler),(r"/logout",LogoutHandler)],template_path=os.path.join(os.path.dirname(__file__),"template"),

                                  static_path=os.path.join(os.path.dirname(__file__),"static"),ui_modules={'Book':HelloModule},cookie_secret=cookie,xsrf_cookies=True,login_url="/login")

    http_server = tornado.httpserver.HTTPServer(app)

    http_server.listen(options.port,address='127.0.0.1')

tornado.ioloop.IOLoop.instance().start()

首先来看下代码的运行原理:

第一步:首先来看WelcomeHandler。这个类的get函数被@tornado.web.authenticated装饰器给装饰,我们进入这个装饰器的代码看下具体的实现:

def authenticated(method):

    @functools.wraps(method)

    def wrapper(self, *args, **kwargs):

        if not self.current_user:

            if self.request.method in ("GET", "HEAD"):

                url = self.get_login_url()

                if "?" not in url:

                    if urlparse.urlsplit(url).scheme:

                        # if login url is absolute, make next absolute too

                        next_url = self.request.full_url()

                    else:

                        next_url = self.request.uri

                    url += "?" + urlencode(dict(next=next_url))

                self.redirect(url)

                return

            raise HTTPError(403)

        return method(self, *args, **kwargs)

    return wrapper

第二步:authenticated首先判断self.current_user是否存在,self.crrent_user的值在tornado.web.RequestHandler中获得。这是一个RequestHandler的类属性。返回的是_current_user,而且_current_user 是通过self.get_current_user()获取的

    @property

    def current_user(self):

        if not hasattr(self, "_current_user"):

            self._current_user = self.get_current_user()

        return self._current_user

而我们在BaseHandler中重写了get_current_user,从客户端发送的cookie中获取username的值。那么如果是第一次访问或者是cookie值失效后,得到的current_user将会是空

    def get_current_user(self):

        return self.get_secure_cookie("username")

第三步:如果current_user为空,网页将重定向到login_url设置的页面连接。url = self.get_login_url()。在这个函数中通过return self.application.settings["login_url"]

返回重定向的url

    def get_login_url(self):

        self.require_setting("login_url", "@tornado.web.authenticated")

        return self.application.settings["login_url"]

第四步:进入登录界面的处理函数LoginHandler。在登录界面中将进行username的cookie值设置

class LoginHandler(BaseHandler):

    def get(self, *args, **kwargs):

        self.render('login.html')

    def post(self, *args, **kwargs):

        self.set_secure_cookie("username",self.get_argument("username"))

第五步:再次登录,由于current_user已经存在,因此跳转到index.html网页,并显示登录的用户名

class WelcomeHandler(BaseHandler):

    @tornado.web.authenticated

    def get(self, *args, **kwargs):

        self.render('index.html',user=self.current_user

代码已经解释完了,我们来看下具体的网页访问例子:

第一步:浏览器中输入http://127.0.0.1:8003/,将会自动跳转到http://127.0.0.1:8003/login?next=%2F

后台打印:

[I 180105 10:11:05 web:2063] 302 GET / (127.0.0.1) 0.33ms

[I 180105 10:11:05 web:2063] 200 GET /login?next=%2F (127.0.0.1) 0.68ms

浏览器中查看cookie值,此时只有设置的_xsrf值

第二步:此时在网页中输入用户名并点击login。再次查看cookie值,已经存在了username的cookie值

第三步 再次登录http://127.0.0.1:8003/。可以看到没有跳转到登录界面,而是直接显示了登录用户。

整个后台的打印:

[I 180105 10:11:05 web:2063] 302 GET / (127.0.0.1) 0.33ms

[I 180105 10:11:05 web:2063] 200 GET /login?next=%2F (127.0.0.1) 0.68ms

[I 180105 10:14:50 web:2063] 200 POST /login (127.0.0.1) 1.46ms

[I 180105 10:16:17 web:2063] 200 GET / (127.0.0.1) 0.64ms

原文地址:https://www.cnblogs.com/zhanghongfeng/p/8202809.html