基本使用
继承,extends 页面总体布局用继承
导入,include 若是是小组件等重复的那么就用导入
下面是目录javascript
首先在controllers里面建立一个文件,文件里面是页面类css
#/usr/bin/env python #-*-coding:utf-8 -*- import tornado.web class IndexHandler(tornado.web.RequestHandler): def get(self,*args,**kwargs): self.render("extend/index.html",List_info=[11,12,13]) class FFHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.render("extend/ff.html",List_info=[11,12,13])
以后在路由系统中配置html
#/bin/usr/env python #-*- coding:utf-8 -*- import tornado.ioloop import tornado.web from controllers import home from settings import Setting from controllers import extend #路由映射,路由系统 application=tornado.web.Application( [#(r"/index/(?P<page>\d*)",home.IndexHandler), (r"/index",extend.IndexHandler), (r"/ff",extend.FFHandler) ], **Setting.settings ) # application.add_handlers("www.cnblogs.com",[ # (r"/index/(?P<page>\d*)",) # ]) if __name__=="__main__": application.listen(8001) tornado.ioloop.IOLoop.instance().start()
配置路由系统以后分别建立继承html包和导入HTML包以及母版文件包前端
建立extend文件包:java
{% extends "../master/layout.html "%} {% block body %} <h1>ff</h1> <h1>end</h1> <!--这里是导入include目录中form文件中的插件内容,注意这里百分号和括号之间不能有空格 若是要用这个插件不少分,那么多导入几回就好了 --> {% include '../include/form.html' %} {% include '../include/form.html' %} {% include '../include/form.html' %} {% end %} { % block js %} <script> console.log("ff") </script> { % end % }
{% extends '../master/layout.html'%} <!--表示替换掉了layout母版中的css内容--> {% block css %} <style> div{ border: 1px solid red; } </style> {% end %} <!--表示替换了母版中和下面相同的内容--> {% block body % } <h1>Index</h1> {% inclue '../include/form.html'%} {% end %} {% block js %} <script> console.log("ss") </script> {% end %}
建立木板文件包masterpython
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> <style> .pg-header{ height: 48px; background-color: papayawhip; } .pg-footer{ height: 100px; background-color: cadetblue; } </style> <!--上面是公用样式,下面是自定义样式--> {% block css %}{% end %} </head> <body> <div class="pg-header"> </div> <div class="pg-content"> {% block body %}{% end %} </div> <div class="pg-footer">adss</div> <script src="xxxj"></script> {% block js %}{% end %} </body> </html>
extend就是方便本身定义代码jquery
include导入文件包web
<form> <input type="text"/> <input type="submit"/> </form> <ul> {% for item in List_info %} <li>{{item}}</li> {% end %} </ul>
这里ff文件导入这个form文件ajax
在导入文件中也能够和后台进行文件渲染,展现给用户,这里List_info就是在index文件中后台返回给前台进行渲染redis
a) 在浏览器端保存的键值对,特性:每次http请求都会携带 b) 实现: i. 用户验证 c) 浏览器: i. tornado,在后台设置 ii. 下面可以用索引取值,是由于tornado在后台进行了分割 1. self.cookies 获取全部的cookies 2. self.get_cookie(“a”) 获取cookie 中key的值 3. self.set_cookie(“key”,”value”) 设置cookie中的值 iii. 在浏览器上使用jacascript来获取cookie 1. document.cookie 表示在当前页面中全部的cookie 2. 要想获取某一个cookie须要本身设置,由于cookie为字符串,因此要用splite进行分割 d) 如: e) document.cookie.split(";") f) ["SRCHD=AF=NOFORM", " SRCHUID=V=2&GUID=6FB4DE80646948698D6D4F6B07F7EFED", " SRCHUSR=DOB=20170405", " MUID=1B4DDEB4557967AE1CDAD4EF54D8662D", " HPBingAppQR=CLOSE=1", " WLS=TS=63627045711", " _SS=SID=2DED841E1D526B202FBB8E421CF36A37&HV=1491448911&bIm=31:152", " SRCHHPGUSR=CW=147&CH=937&DPR=1&UTC=480"] 3、document.cookie=”k1=xx;path=/;domin(域名):expires” 在浏览器页面设置cookie,而且带上路径
JavaScript操做Cookie
因为Cookie保存在浏览器端,因此在浏览器端也可使用JavaScript来操做Cookie。
/* toUTCString() 方法可根据世界时 (UTC) 把 Date 对象转换为字符串,并返回结果 设置cookie,指定秒数过时 */ function setCookie(name,value,expires){ var temp = []; var current_date = new Date(); 获取当前时间 // current_date.getSeconds() 获取当前秒 // current_date.setSeconds 设置秒 //data.setDate(data.getDate()+7),表示获取超过如今7天的时间 // current_date 当前时间+5秒 // toUTCString() 当前统一时间 current_date.setSeconds(current_date.getSeconds() + 5); document.cookie = name +"= "+ value +";expires="+ current_date.toUTCString(); }
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title></title> </head> <body> <h1>adasd</h1> <script> /* 设置cookie,指定秒数过时 */ function setCookie(name,value,expires){ var temp = []; var current_date = new Date(); current_date.setSeconds(current_date.getSeconds() + 5); document.cookie = name + "= "+ value +";expires=" + current_date.toUTCString(); } </script> </body> </html> 而后在浏览器中访问 setCookie("k22=11",5) 设置cookie,超时时间为5秒 undefined document.cookie 查看cookie "k1=999; k22=11= 5" document.cookie 5秒后查看 "k1=999"
对于参数
jquery中设置cookie
要用须要下载 这里
1、 导入jquery 2、 导入jQuery Cookie Plugin v1.4.1 注意点: 若是用jquery导入的时候expires这里若是为数字的时候,表示天数 若是不想用天数,那么要用,这里的超时时间必需要用toUTCString()统一时间 current_date.setSeconds(current_date.getSeconds() + 5); 用天数,而后用字符串拼接的方式";expires="+ current_date.toUTCString() 等来设置时间,js数组的.join方法是吧数组变成字符串 $.cookie(“k1”,”22”,{“path”:””,”domin”:””,expires=1}) 上面的cookie中的数组,在内部用了join方法分割成了字符串
tornado带签名的cookie原理图
tornado支持两种方式
首先服务端让浏览器端生成cookie的时候会通过base64加密,首先生成加密串, 注意这里的当前时间是 >>> import time >>> time.time() 1491471613.5271676 --->生成的这个值就是当前时间 >>> 加密串 =v1(value)+当前时间+内部自定义字符串 以后生成的这个cookie就是k1(key)=v1|加密串|当前时间 如何验证这个cookie有没有被篡改: 客户端向浏览器端发送请求:会把v1和加密串和当前时间发送给浏览器,浏览器内部会通过md5生成一个新的加密串
自定义字符串+发送过来的时间+v1等于新的加密串,而后加密串进行对比,若是一致就能经过
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): #这里判断判断用户登陆 def get(self): if self.get_argument("u",None) in ["aa","eric"]: self.set_cookie("name",self.get_argument("u")) # self.set_secure_cookie("name",self.get_argument("u")) else: self.write("请登陆") class ManagerHandler(tornado.web.RequestHandler): #若是有cookie的时候就登陆 def get(self): if self.get_cookie("name",None) in ["aa","eric"]: self.write("欢迎登陆:"+self.get_cookie("name")) else: self.redirect("/index") settings={ "template_path":"views", "static_path":"statics" } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start() 上面就是用一种简单的模式登陆,登陆的时候 在浏览器中输入 http://127.0.0.1:8000/index?u=aa 以后就会执行IndexHandler方法中的get方法首先存入用户输入的cookie,对比后台,而后访问manager网站的时候,判断,若是有对应的cookie那么就会出现欢迎登陆
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web class IndexHandler(tornado.web.RequestHandler): #这里判断判断用户登陆 def get(self): if self.get_argument("u",None) in ["alex","eric"]: 这里设置加密的cookie self.set_secure_cookie("user",self.get_argument("u")) else: self.write("请登陆") class ManagerHandler(tornado.web.RequestHandler): #若是有cookie的时候就登陆 def get(self): 获取加密的cookie if str(self.get_secure_cookie("user",None),encoding="utf-8") in ["alex","eric"]: self.write("欢迎登陆:"+str(self.get_secure_cookie("user"))) else: self.redirect("/index") settings={ "template_path":"views", "static_path":"statics", 这必须设置配置 "cookie_secret":"hello", } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start() 设置加密的cookie用set_secure_cookie()方法,若是获取cookie的时候用get_secure_cookie() 注意这里获取加密cookie 注意:这里获取的cookie是byte类型,因此必需要转换一下类型
Cookie 很容易被恶意的客户端伪造。加入你想在 cookie 中保存当前登录用户的 id 之类的信息,
你须要对 cookie 做签名以防止伪造。Tornado 经过 set_secure_cookie 和 get_secure_cookie
方法直接支持了这种功能。 要使用这些方法,你须要在建立应用时提供一个密钥,名字为 cookie_secret。
你能够把它做为一个关键词参数传入应用的设置中
签名Cookie的本质是: 写cookie过程: 将值进行base64加密 对除值之外的内容进行签名,哈希算法(没法逆向解析) 拼接 签名 + 加密值 读cookie过程: 读取 签名 + 加密值 对签名进行验证 base64解密,获取值内容 注:许多API验证机制和安全cookie的实现机制相同
1 若是一直用加密的cookie一直给浏览器那么会致使不安全,以及流量的增大 2 用一段cookie来表明帐号密码,邮箱等等 3 tornado里面默认没有session,django里面有session 4 5 补充知识: 6 hashlib.md5.digest() 7 hashlib.hexdigest() 8 是生成MD5的两种表现形式,hashlib.md5.digest() 加密后的结果用二进制表示 9 二进制由0和1组成,一个字节包含8位二进制码,即包含8位0或1, 1byte可用2个16进制的数来表示 10 电脑中的数据都是按照16进制来保存的 11 因此这里要用hexdigest来生成随机数 12 a[aa]={}:表示a为字典。aa为a的key值,后面的{}表示a中aa为key的value的值 13 14 container内容能够放到1在内存,2在数据库,3在缓存
上图:但用户k1访问服务器的时候会生成aa这个字符串,aa这个字符串保存着用户的各类信息,但用户k2访问服务器的时候,在内部生成bb字符串,用来保存用户的各类信息
。
session其实就是定义在服务器端用于保存用户回话的容器,其必须依赖cookie才能实现。
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web #这个字典必须定制成为全局变量用来保存用户的信息,若是是局部变量, # 那么http请求断开下次用户登陆这个用户信息就会消失 container={} class IndexHandler(tornado.web.RequestHandler): #这里判断判断用户登陆 def get(self): if self.get_argument("u",None) in ["aa","eric"]: import hashlib import time #首先经过md5生成随机数据,电脑中的数据都是16进制保存的 obj=hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str=obj.hexdigest() container[random_str]={} container[random_str]["k1"]=123 #加上自定义字符串 container[random_str]["k2"]=self.get_argument("u",None)+"parents" #本身定义的,但愿之后is_login来肯定用户是否上线登陆 container[random_str]["is_login"]=True #把cookie发送给客户端 self.set_cookie("iii",random_str) else: self.write("请登陆") class ManagerHandler(tornado.web.RequestHandler): def get(self): random_str=self.get_cookie("iii") #获取key对应的值,默认为None current_user_info=container.get(random_str,None) if not current_user_info: self.redirect("/index") else: if current_user_info.get("is_login",None): temp="%s-%s"%(current_user_info.get("k1",""),current_user_info.get("k2","")) self.write(temp) else: self.redirect("/index") settings={ "template_path":"views", "static_path":"statics", "cookie_secret":"hello", } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
1、 首先建立session这个容器,让这个容器定义为全局变量 2、 以后建立随机数,而且让这个随机数定义为字典 3、 在随机数定义的字典里面,分别定义三类,一类是本来的信息,第二类是让数据加上自定义字符串,第三类标志位 4、 给客户端发送cookie 5、 而后用户链接的时候分别判断,随机数,和标志位 自定义session至关于本身开发httpd三次握手
session优化封装
上面每个用户链接都会生成一个随机数,而且随机数(表明字典)里面会保存用户的信息
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web #这个字典必须定制成为全局变量用来保存用户的信息,若是是局部变量, # 那么http请求断开下次用户登陆这个用户信息就会消失 container={} #把Sesson封装起来 class Session: #为了引入IndexHandler的方法,这里的self表明的是s对象 def __init__(self,handler): self.handler=handler def __genarate_random_str(self): #建立随机字符串 import hashlib import time #首先经过md5生成随机数据,电脑中的数据都是16进制保存的 obj=hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str=obj.hexdigest() return random_str def set_value(self,key,value): #在container中加入随机字符串,以前要建立随机字符串 #定义专属于本身的数据 #在客户端写入随机字符串 #判断,请求的用户是否已经有随机字符串 random_str=self.handler.get_cookie("__kakaka__") container[random_str]={} container[random_str][key]=value #这里是为写超时时间作准备 self.handler.set_cookie("__kakaka__",random_str) def get_value(self,key): #获取值 #首先获取客户端的随机字符串 #从container中获取专属于个人数据 #专属个人数据[key] random_str=self.handler.get_cookie("__kakaka__") user_info_dict=container[random_str] value=user_info_dict[key] return value class IndexHandler(tornado.web.RequestHandler): #这里判断判断用户登陆 def get(self): if self.get_argument("u",None) in ["aa","eric"]: s=Session(self) s.set_value("is_login",True) else: self.write("请登陆") class ManagerHandler(tornado.web.RequestHandler): def get(self): s=Session(self) val=s.get_value("is_login") if val: self.write("成功") else: self.write("请从新登陆") settings={ "template_path":"views", "static_path":"statics", "cookie_secret":"hello", } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
这段代码是把上面的方法进行了封装,流程: 1、 用户访问index这个网站,其实就是访问了IndexHandler这个类,会执行get方法,获取用户输入的内容,若是输入的内容符合条件 2、 初始化Session类中的__init__方法,而后执行set_value方法,而且把传入参数is_login 3、获取随机数,清空随机数这个字典中的内容,而后把参数传递进去,而且把cookie传递给浏览器
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web #这个字典必须定制成为全局变量用来保存用户的信息,若是是局部变量, # 那么http请求断开下次用户登陆这个用户信息就会消失 container={} #把Sesson封装起来 class Session: def __init__(self,handler): self.handler=handler self.random_str=None #用户链接初始化随机数 def __genarate_random_str(self): #建立随机字符串 import hashlib import time #首先经过md5生成随机数据,电脑中的数据都是16进制保存的 obj=hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str=obj.hexdigest() return random_str def set_value(self,key,value): #这里判断若是服务端没有随机数 if not self.random_str: #用户链接,首先服务端没有随机数,那么去客户端拿随机数 random_str=self.handler.get_cookie("__kakaka__") #去客户端中拿随机数 if not random_str: #若是客户端也没有随机数,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() #建立随机数 container[random_str]={} #清空随机数字典中的内容 else: if random_str in container.keys(): #若是客户端有随机数,而且为真那么就直接登陆成功 pass else: #若是客户端到的随机数是伪造的,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() container[random_str]={} self.random_str=random_str #最后把上面判断出来的随机数传递给类 container[self.random_str][key]=value #这里是为写超时时间作准备 self.handler.set_cookie("__kakaka__",self.random_str) #设置cookie给浏览器,这里能够设置超时时间 def get_value(self,key): #获取值 random_str=self.handler.get_cookie("__kakaka__") if not random_str:#若是客户端没有随机字符串,就结束 return None user_info_dict=container.get(random_str,None)#客户端有随机字符串,可是内容服务器不匹配,就退出 if not user_info_dict: return None value=user_info_dict.get(key,None) #前面若是都知足,有值就拿值,没有就为None return value class IndexHandler(tornado.web.RequestHandler): #这里判断判断用户登陆 def get(self): if self.get_argument("u",None) in ["aa","eric"]: s=Session(self) s.set_value("is_login",True) s.set_value("name",self.get_argument("u",None)) else: self.write("请登陆") class ManagerHandler(tornado.web.RequestHandler): def get(self): s=Session(self) val=s.get_value("is_login") if val: self.write(s.get_value("name")) else: self.write("请从新登陆") settings={ "template_path":"views", "static_path":"statics", "cookie_secret":"hello", } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
用户若是直接链接manager会提示必须登陆,主要缘由是浏览器cookie中没有登陆信息 1、 用户访问index网页的时候就是访问IndexHandler这个类,用户链接,服务器内部就会初始化随机数 2、 服务器就会执行set_value方法,而且传入参数is_login参数,首先为了判断用户是否第一次登录,因此用if not self.random_str,没有就用get_cookie()方法去客户端中拿随机数,这里须要判断,若是客户端也没有随机数,那么服务端就要本身建立随机数,而且把这个随机数传递给服务器这个类;若是客户端有随机数,要判断这个随机数是不是伪造的,若是是伪造的,服务器须要本身建立随机数,而且把这个随机数传递给服务器这个类;以后把is_login参数替代key传递给session这个字典求出来value这个值,而且设置一下这个cookie传递给浏览器;而后设置key为name的cookie 3、 用户访问manager这个网站,会执行get方法,而且获取浏览器随机数,若是浏览器中没有随机数或者浏览器的随机数是伪造的,那么就会退出,若是通过了2这个步骤,那么就能登陆成功而且获得设置cookie中key为name的值
优化:
在Tornado框架中,默认执行Handler的get/post等方法以前默认会执行 initialize方法,因此能够经过自定义的方式使得全部请求在处理前执行操做
这里的initialize就是钩子函数
优化一
#定义tornado中的钩子函数和反射函数来优化下面的类 class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session=Session(self) class IndexHandler(BaseHandler): #这里判断判断用户登陆,get方法是被反射调用的getattr def get(self): if self.get_argument("u",None) in ["aa","eric"]: self.session.set_value("is_login",True) self.session.set_value("name",self.get_argument("u",None)) else: self.write("请登陆") class ManagerHandler(BaseHandler): def get(self): val=self.session.get_value("is_login") if val: self.write(self.session.get_value("name")) else: self.write("请从新登陆")
让这两个类继承一个共同的父类,利用tornado内置的钩子函数来优化代码
优化2、利用__getitem__ __setitem__方法
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web #这个字典必须定制成为全局变量用来保存用户的信息,若是是局部变量, # 那么http请求断开下次用户登陆这个用户信息就会消失 container={} #把Sesson封装起来 class Session: def __init__(self,handler): self.handler=handler self.random_str=None #用户链接初始化随机数 def __genarate_random_str(self): #建立随机字符串 import hashlib import time #首先经过md5生成随机数据,电脑中的数据都是16进制保存的 obj=hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str=obj.hexdigest() return random_str def __setitem__(self,key,value): #这里判断若是服务端没有随机数 if not self.random_str: #用户链接,首先服务端没有随机数,那么去客户端拿随机数 random_str=self.handler.get_cookie("__kakaka__") #去客户端中拿随机数 if not random_str: #若是客户端也没有随机数,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() #建立随机数 container[random_str]={} #清空随机数字典中的内容 else: if random_str in container.keys(): #若是客户端有随机数,而且为真那么就直接登陆成功 pass else: #若是客户端到的随机数是伪造的,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() container[random_str]={} self.random_str=random_str #最后把上面判断出来的随机数传递给类 container[self.random_str][key]=value #这里是为写超时时间作准备 self.handler.set_cookie("__kakaka__",self.random_str) #设置cookie给浏览器,这里能够设置超时时间 def __getitem__(self,key): #获取值 random_str=self.handler.get_cookie("__kakaka__") if not random_str:#若是客户端没有随机字符串,就结束 return None user_info_dict=container.get(random_str,None)#客户端有随机字符串,可是内容服务器不匹配,就退出 if not user_info_dict: return None value=user_info_dict.get(key,None) #前面若是都知足,有值就拿值,没有就为None return value #定义tornado中的钩子函数和反射函数来优化下面的类 class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session=Session(self) class IndexHandler(BaseHandler): #这里判断判断用户登陆,get方法是被反射调用的getattr def get(self): if self.get_argument("u",None) in ["aa","eric"]: self.session["is_login"]=True self.session["name"]=self.get_argument("u",None) # self.session.set_value("is_login",True) # self.session.set_value("name",self.get_argument("u",None)) else: self.write("请登陆") class ManagerHandler(BaseHandler): def get(self): val=self.session["is_login"] if val: self.write(self.session["name"]) else: self.write("请从新登陆") settings={ "template_path":"views", "static_path":"statics", "cookie_secret":"hello", } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler) ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
全部的web框架都是session[key]=value的方法实现的
这里只须要改一下名字就能够
1、 placeholder 属性提供可描述输入字段预期值的提示信息(hint)。 该提示会在输入字段为空时显示,并会在字段得到焦点时消失。 2、 open打开一个文件的时候里面要加上r表示不用转义了 open(r”路径”)
验证码原理在于后台自动建立一张带有随机内容的图片,而后将内容经过img标签输出到页面。
这个验证码是放在tornado的session里面的
验证码机制:服务器首先建立验证码,而且把验证码放入到随机数这个字典里面,用户经过get方法接收到验证码,而后用户输入验证码和帐户信息发送给服务器,服务器经过对比用户发来的验证码和本身产生的验证码,(这里要建立不分辨大小写,可让用户输入的和本身产生的转成所有大写或者所有小写)对比,若是同样那么就显示登陆成功,若是没有同样,那么就显示输入的验证码错误。而且在前端添加一个点击事件,只要用户一点击那么验证码就会刷新
安装图像处理模块:
1 |
pip3 install pillow |
下载下面源码以后,须要把check_code.py和Monaco.ttf导入到这个代码目录中(仅仅限制与python3.5)
<!DOCTYPE html> <html> <head lang="en"> <meta charset="UTF-8"> <title></title> <style> .aa{ cursor: pointer; } </style> </head> <body> <h1>请输入登陆信息</h1> <form action="/login" method="post"> <p><input name="user" type="text" placeholder="用户名" /></p> <p><input name="pwd" type="password" placeholder="密码" /></p> <p> <input name='code' type="text" placeholder="验证码" /> <img class="aa" src="/check_code" onclick='ChangeCode();' id='imgCode'> </p> <input type="submit" value="提交"/><span style="color: red">{{status}}</span> </form> <script type="text/javascript"> function ChangeCode() { var code = document.getElementById('imgCode'); //url后面只能添加问号,添加问号就是改变地址 code.src += '?'; } </script> </body> </html>
#/usr/bin/env python #-*- coding:utf-8-*- import tornado.ioloop import tornado.web import tornado.httpserver import tornado.ioloop import tornado.process import tornado.web # #这个字典必须定制成为全局变量用来保存用户的信息,若是是局部变量, # 那么http请求断开下次用户登陆这个用户信息就会消失 container={} #把Sesson封装起来 class Session: def __init__(self,handler): self.handler=handler self.random_str=None #用户链接初始化随机数 def __genarate_random_str(self): #建立随机字符串 import hashlib import time #首先经过md5生成随机数据,电脑中的数据都是16进制保存的 obj=hashlib.md5() obj.update(bytes(str(time.time()),encoding="utf-8")) random_str=obj.hexdigest() return random_str def __setitem__(self,key,value): #这里判断若是服务端没有随机数 if not self.random_str: #用户链接,首先服务端没有随机数,那么去客户端拿随机数 random_str=self.handler.get_cookie("__kakaka__") #去客户端中拿随机数 if not random_str: #若是客户端也没有随机数,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() #建立随机数 container[random_str]={} #清空随机数字典中的内容 else: if random_str in container.keys(): #若是客户端有随机数,而且为真那么就直接登陆成功 pass else: #若是客户端到的随机数是伪造的,那么服务端就本身建立随机数 random_str=self.__genarate_random_str() container[random_str]={} self.random_str=random_str #最后把上面判断出来的随机数传递给类 container[self.random_str][key]=value #这里是为写超时时间作准备 self.handler.set_cookie("__kakaka__",self.random_str) #设置cookie给浏览器,这里能够设置超时时间 def __getitem__(self,key): #获取值 random_str=self.handler.get_cookie("__kakaka__") if not random_str:#若是客户端没有随机字符串,就结束 return None user_info_dict=container.get(random_str,None)#客户端有随机字符串,可是内容服务器不匹配,就退出 if not user_info_dict: return None value=user_info_dict.get(key,None) #前面若是都知足,有值就拿值,没有就为None return value #定义tornado中的钩子函数和反射函数来优化下面的类 class BaseHandler(tornado.web.RequestHandler): def initialize(self): self.session=Session(self) class IndexHandler(BaseHandler): #这里判断判断用户登陆,get方法是被反射调用的getattr def get(self): if self.get_argument("u",None) in ["aa","eric"]: self.session["is_login"]=True self.session["name"]=self.get_argument("u",None) # self.session.set_value("is_login",True) # self.session.set_value("name",self.get_argument("u",None)) else: self.write("请登陆") class ManagerHandler(BaseHandler): def get(self): val=self.session["is_login"] if val: self.write(self.session["name"]) else: self.write("请从新登陆") # class CheckCodeHandler(BaseHandler): # def get(self): # import io # import check_code # # mstream = io.BytesIO() # img, code = check_code.create_validate_code() # img.save(mstream, "GIF") # # self.session["CheckCode"] = code # self.write(mstream.getvalue()) class MainHandler(BaseHandler): def get(self): self.render('login.html',status="") def post(self, *args, **kwargs): user=self.get_argument("user",None) pwd=self.get_argument("pwd",None) code=self.get_argument("code",None) #比较用户输入的验证码和服务器给出的验证码的值 check_code=self.session["CheckCode"] if code.upper()==check_code.upper(): self.write("验证码正确") else: # self.redirect("/login") self.render("login.html",status="验证码错误") class CheckCodeHandler(BaseHandler): def get(self, *args, **kwargs): #生成图片而且返回 import io import check_code #创建内存级别文件,至关于一个容器 mstream = io.BytesIO() #建立图片而且写入验证码 img, code = check_code.create_validate_code() #将图片内容写入到IO中mstream img.save(mstream, "GIF") #为每一个用户保存其对应的验证码 self.session["CheckCode"] = code self.write(mstream.getvalue()) settings={ 'template_path': 'views', 'static_path': 'static', "static_url_prefix":"/statics/", "cookie_secret":"hello", # "xsrf_cookies":True, } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler), # (r"/login",LoginHandler), (r"/login",MainHandler), (r"/check_code",CheckCodeHandler), ],**settings) if __name__=="__main__": application.listen(8000) tornado.ioloop.IOLoop.instance().start()
验证码Demo源码下载:猛击这里
会集群要会:分布式哈希haxi redis
CSRF限制post请求的
用户访问是先请求服务器调用get请求,而后发送post请求,以后服务器会给用户一个随机字符串,当用户离开后,下次再访问会带着这个随机字符串访问服务器,若是用户没有这个随机字符串,那么CSRF会阻止这个用户请求,这样可使服务器免遭受恶意攻击形成服务器宕机
要加上CSRF:
一、在配置文件中加上配置文件”xsrf_cookies”:True
二、在前台代码中加上{% raw xsrf__form_html %}
class CsrfHandler(BaseHandler): def get(self, *args, **kwargs): self.render("csrf.html") def post(self, *args, **kwargs): self.write("csrf.post") settings={ 'template_path': 'views', 'static_path': 'static', "static_url_prefix":"/statics/", "cookie_secret":"hello", "xsrf_cookies":True, 这里加上配置文件 } application=tornado.web.Application([ (r"/index",IndexHandler), (r"/manager",ManagerHandler), # (r"/login",LoginHandler), (r"/login",MainHandler), (r"/check_code",CheckCodeHandler), (r"/csrf",CsrfHandler) ],**settings)
html代码上面加上
<form action="/csrf" method="post"> {% raw xsrf_form_html() %} <p><input type="text" placeholder="用户"/></p> <p><input type="text" placeholder="密码"/></p> <p> <input name="code" type="text" placeholder="验证码"/> <!--<img src="/check_code">--> </p> <input type="submit" value="Submit"/>
提交的是AJAX的post请求
若是你提交的是 AJAX 的 POST
请求,你仍是须要在每个请求中经过脚本添加上 _xsrf
这个值。下面是在 FriendFeed 中的 AJAX 的 POST
请求,使用了 jQuery 函数来为全部请求组东添加 _xsrf
值:
function getCookie(name) { var r = document.cookie.match("\\b" + name + "=([^;]*)\\b"); return r ? r[1] : undefined; } jQuery.postJSON = function(url, args, callback) { args._xsrf = getCookie("_xsrf"); $.ajax({url: url, data: $.param(args), dataType: "text", type: "POST", success: function(response) { callback(eval("(" + response + ")")); }}); };
对于 PUT
和 DELETE
请求(以及不使用将 form 内容做为参数的 POST
请求) 来讲,你也能够在 HTTP 头中以 X-XSRFToken
这个参数传递 XSRF token。
若是你须要针对每个请求处理器定制 XSRF 行为,你能够重写 RequestHandler.check_xsrf_cookie()
。例如你须要使用一个不支持 cookie 的 API, 你能够经过将 check_xsrf_cookie()
函数设空来禁用 XSRF 保护机制。然而若是 你须要同时支持 cookie 和非 cookie 认证方式,那么只要当前请求是经过 cookie 进行认证的,你就应该对其使用 XSRF 保护机制,这一点相当重要。
1、cookie和session的区别 1)cookie是保存在客户端的,session是保存在服务端的,由于服务器端,表示可能在内存中,可能在数据库端,可能在缓存中统称为服务器端 2、session和cookie有什么联系?: 答:有。session是经过cookie人为构建起来的,在web开发里面自己没有session这个东西的。在服务器端能够高层一个数据库,能够在内存中搞成一个字典,每一次用户来访问的时候,给用户发一对token,下一次,用户访问再带着这一对token来,服务器端就知道你是否是上一次的你。若是再问就来画一张图 3、分页 XSS 跨站脚本攻击 4、csrf 工做方式: 答:跨站请求伪造 验证:第一次请求的时候是get方式请求,防止没有通过验证就来post请求,形成大并发机器宕机 5、 Ajax 为何要有Ajax 答:防止页面批量刷新 利用: iframe 忽略 XMLHttpRequest 本身写 xhr xhr.open() xhr.onreadystatechange xhr.send() jQuery 会用下面的就会jquery,ajax $.ajax({ url: type data dataType success error }) 6、 验证码、 7、 上传文件 form标签 form标签 enctype=““form标签里面必需要有这个才能进行上传文件 经过Ajax上传文件 利用formDate() XMLHttpRequest jQuery iframe+form标签为了兼容性设计,ifram就至关于设置一个通道,form把数据提交到这个通道,而后不刷页面上传文件