在这个例子中,我们将只通过存储在安全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

tornado安全应用之用户认证的更多相关文章

  1. Tornado web.authenticated 用户认证浅析

    在Web服务中会有用户登录后的一系列操作, 如果一个客户端的http请求要求是用户登录后才能做得操作, 那么 Web服务器接收请求时需要判断该请求里带的数据是否有用户认证的信息. 使用Tornado框 ...

  2. Nodejs之MEAN栈开发(八)---- 用户认证与会话管理详解

    用户认证与会话管理基本上是每个网站必备的一个功能.在Asp.net下做的比较多,大体的思路都是先根据用户提供的用户名和密码到数据库找到用户信息,然后校验,校验成功之后记住用户的姓名和相关信息,这个信息 ...

  3. Django--自定义用户认证

    Django自带的用户认证 以前都是用Django自带的用户认证,用户名字段一对一关系对应Django--User表(其实它也是继承了abstractbaseuser). 1 2 3 from dja ...

  4. linux(十二)___Apache服务器用户认证、虚拟主机的配置

    创建xiangkejin  zhangsan两个用户 可看见文件中创建的两个用户: 建立虚拟目录并配置用户认证 ①建立虚拟目录 /xiangkejin ②在Apache的主配置文件httpd.conf ...

  5. [django]用户认证中只允许登陆用户访问(网页安全问题)

    当设计一个重要网页时,一般要求未从登陆界面访问的用户不能进入其他页面,那么需要如何设置呢? 如下 django中的url.py urlpatterns = [    url(r'^$', 'login ...

  6. 使用JDBC实现Oracle用户认证

    两天时间写的小品,以前的J2EE环境基本使用框架.现在使用JDBC配合Oracle存储过程模拟了一下用户注册和用户认证. 一.添加必须的jar包 需要JDBC连接Oracle的包和shiro-core ...

  7. ldap实现用户认证

    LDAP的用户认证类. public class LDAPHelper { private DirectoryEntry _objDirectoryEntry; /// <summary> ...

  8. auth用户认证库

    关于auth库,建议如下:1. ion_auth,基于Redux重写而成,非常不错的认证库,国外用的很多,几个最新的ci2.0.2基础上的开源系统(如doveforum)都用它,支持ci 2.0和以上 ...

  9. 禅道PMS兼容redmine用户认证接口

    项目地址:https://github.com/web3d/zentao-redmine-userauth zentao-redmine-userauth 做了一个基本的用户认证接口,兼容redmin ...

随机推荐

  1. 系统虚拟内存的理解 转载自http://blog.csdn.net/do2jiang/article/details/4690967

    在进入正题前先来谈谈操作系统内存管理机制的发展历程,了解这些有利于我们更好的理解目前操作系统的内存管理机制. 一 早期的内存分配机制 在 早期的计算机中,要运行一个程序,会把这些程序全都装入内存,程序 ...

  2. Yii createCommand CURD操作

    本文用作工作记录,也许有人会问为什么不用 Yii 的 Model 去操作 DB,原因很简单,Yii 的 Model 写法上是方便了很多,但是会执行多余的 SQL,打开 Yii 的执行 log 就会发现 ...

  3. Codeforces 620F Xors on Segments(暴力+DP)

    题目链接 Xors on Segments 预处理出$x[i]$ $=$ $1$ $xor$ $2$ $xor$ $3$ $xor$ $……$ $xor$ $i$ 话说这题$O(n^{2})$居然能过 ...

  4. vue常用指命

    1.v-text:用于更新标签包含的文本,作用和{{}}的效果一样. 2.v-html:绑定一些包含html代码的数据在视图上. 3.v-show:用来控制元素的display属性,和显示隐藏有关.v ...

  5. MySQL中数据类型(char(n)、varchar(n)、nchar(n)、nvarchar(n)的区别)(转)

    一.第一种 char(n)和varchar(n)的区别: 在这里我们可以清楚的看到他们表面的区别就是前面是否有var,在这里解释一下var是什么意思,var代表“可变的”的意思 下面看个例子: )// ...

  6. input 对伪元素(:before :after)的支持情况

    最近做一个自定义视觉效果的Switch组件,用到了 input:radio 和 label,并在label里用伪元素 :before 模拟状态的切换效果. 但是同事评审的时候说可以不用label,直接 ...

  7. ADO如何记录SQL日志

    ADO如何记录SQL日志 procedure TfrmDM.ADOConnection1WillExecute(Connection: TADOConnection; var CommandText: ...

  8. arcgis andriod Edit features

    来自:https://developers.arcgis.com/android/guide/edit-features.htm#ESRI_SECTION1_56C60DB71AF941E98668A ...

  9. JSP/SERVLET新手教程--Servlet 使用入门

    如今的JSP书籍有的是直接讲述JSP的使用,然后再解说SERVERLET的使用;也有书籍是先讲述SERVERLET的使用,然后解说JSP使用.个人觉得另外一种相对好一些,至于原因大家能够在学习体会到! ...

  10. python matplotlib 绘图 和 dpi对应关系

    dpi=1 600×400 dpi=2 1200×800 dpi=3 1800×1200 ........ dpi=21 (21×600)×(21×400) ---> 12600×8400 示例 ...