web框架詳解之 tornado 四 模板引擎、session、驗證碼、xss

1、模板引擎

基本使用
    繼承,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])
extend代碼

以後在路由系統中配置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()
start.py代碼

配置路由系統以後分別建立繼承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 % }
ff文件代碼
{% 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 %}
index文件代碼

建立木板文件包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>
layout母版文件

extend就是方便本身定義代碼jquery

include導入文件包web

<form>
    <input type="text"/>
    <input type="submit"/>
</form>

<ul>
    {% for item in List_info %}
    <li>{{item}}</li>
    {% end %}
</ul>
form文件

這裏ff文件導入這個form文件ajax

在導入文件中也能夠和後臺進行文件渲染,展現給用戶,這裏List_info就是在index文件中後臺返回給前臺進行渲染redis

2、cookie

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();
}
View Code
<!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"
HTML代碼

對於參數

  • domain   指定域名下的cookie
  • path       域名下指定url中的cookie
  • secure    https使用

 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方法分割成了字符串
View Code

tornado帶簽名的cookie原理圖

tornado支持兩種方式

  • 1、簡單的方式
  • 2、簽名的方式

首先服務端讓瀏覽器端生成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那麼就會出現歡迎登陸
基於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 很容易被惡意的客戶端僞造。加入你想在 cookie 中保存當前登錄用戶的 id 之類的信息,
你須要對 cookie 做簽名以防止僞造。Tornado 經過 set_secure_cookie 和 get_secure_cookie
方法直接支持了這種功能。 要使用這些方法,你須要在建立應用時提供一個密鑰,名字爲 cookie_secret。
你能夠把它做爲一個關鍵詞參數傳入應用的設置中
簽名Cookie的本質是:

寫cookie過程:

將值進行base64加密
對除值之外的內容進行簽名,哈希算法(沒法逆向解析)
拼接 簽名 + 加密值
讀cookie過程:

讀取 簽名 + 加密值
對簽名進行驗證
base64解密,獲取值內容
注:許多API驗證機制和安全cookie的實現機制相同
總結

3、自定義web組件session

 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在緩存
View Code

上圖:但用戶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()
python代碼
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()
python代碼
這段代碼是把上面的方法進行了封裝,流程:
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()
session優化:
用戶若是直接鏈接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("請從新登陸")
View Code

讓這兩個類繼承一個共同的父類,利用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()
View Code

全部的web框架都是session[key]=value的方法實現的

這裏只須要改一下名字就能夠

1、
placeholder 屬性提供可描述輸入字段預期值的提示信息(hint)。
該提示會在輸入字段爲空時顯示,並會在字段得到焦點時消失。
2、
open打開一個文件的時候裏面要加上r表示不用轉義了
open(r」路徑」)
補充知識:

4、驗證碼

驗證碼原理在於後臺自動建立一張帶有隨機內容的圖片,而後將內容經過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>
login.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()
python代碼

驗證碼Demo源碼下載:猛擊這裏

 

5、CSRF

會集羣要會:分佈式哈希haxi redis
CSRF限制post請求的
用戶訪問是先請求服務器調用get請求,而後發送post請求,以後服務器會給用戶一個隨機字符串,當用戶離開後,下次再訪問會帶着這個隨機字符串訪問服務器,若是用戶沒有這個隨機字符串,那麼CSRF會阻止這個用戶請求,這樣可使服務器免遭受惡意攻擊形成服務器宕機
View Code

要加上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)
View Code

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"/>
View Code

提交的是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 保護機制,這一點相當重要。

 6、總結

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把數據提交到這個通道,而後不刷頁面上傳文件
重點總結
相關文章
相關標籤/搜索