基本使用
繼承,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把數據提交到這個通道,而後不刷頁面上傳文件