1. 程式人生 > >tornado 驗證碼生成+結合session進行登入驗證

tornado 驗證碼生成+結合session進行登入驗證

第一、生成驗證碼圖片

 生成驗證碼圖片需要兩個必須模組

  1、python自帶的random(隨機模組)

  2、Pillow()影象處理模組裡的PIL(影象庫),為第三方模組,需要安裝

封裝驗證碼圖片生成外掛py

在封裝檔案裡先匯入random(隨機模組),和Pillow()影象處理模組裡的所需py檔案

封裝驗證碼圖片生成外掛功能,呼叫後返回驗證碼圖片,和字串型別驗證碼兩個返回值

注意:驗證碼需要一個字型檔案,這個字型檔案必須和封裝建立放在一起

驗證碼圖片生成外掛py

#!/usr/bin/env python
#coding:utf-8

import random
from PIL import Image, ImageDraw, ImageFont, ImageFilter

_letter_cases = "abcdefghjkmnpqrstuvwxy"  # 小寫字母,去除可能干擾的i,l,o,z
_upper_cases = _letter_cases.upper()  # 大寫字母
_numbers = ''.join(map(str, range(3, 10)))  # 數字
init_chars = ''.join((_letter_cases, _upper_cases, _numbers))

def create_validate_code(size=(120, 30),
                         chars=init_chars,
                         img_type="GIF",
                         mode="RGB",
                         bg_color=(255, 255, 255),
                         fg_color=(0, 0, 255),
                         font_size=18,
                         font_type="Monaco.ttf",
                         length=4,
                         draw_lines=True,
                         n_line=(1, 2),
                         draw_points=True,
                         point_chance = 2):
    '''
    @todo: 生成驗證碼圖片
    @param size: 圖片的大小,格式(寬,高),預設為(120, 30)
    @param chars: 允許的字元集合,格式字串
    @param img_type: 圖片儲存的格式,預設為GIF,可選的為GIF,JPEG,TIFF,PNG
    @param mode: 圖片模式,預設為RGB
    @param bg_color: 背景顏色,預設為白色
    @param fg_color: 前景色,驗證碼字元顏色,預設為藍色#0000FF
    @param font_size: 驗證碼字型大小
    @param font_type: 驗證碼字型,預設為 ae_AlArabiya.ttf
    @param length: 驗證碼字元個數
    @param draw_lines: 是否劃干擾線
    @param n_lines: 干擾線的條數範圍,格式元組,預設為(1, 2),只有draw_lines為True時有效
    @param draw_points: 是否畫干擾點
    @param point_chance: 干擾點出現的概率,大小範圍[0, 100]
    @return: [0]: PIL Image例項
    @return: [1]: 驗證碼圖片中的字串
    '''

    width, height = size # 寬, 高
    img = Image.new(mode, size, bg_color) # 建立圖形
    draw = ImageDraw.Draw(img) # 建立畫筆

    def get_chars():
        '''生成給定長度的字串,返回列表格式'''
        return random.sample(chars, length)

    def create_lines():
        '''繪製干擾線'''
        line_num = random.randint(*n_line) # 干擾線條數

        for i in range(line_num):
            # 起始點
            begin = (random.randint(0, size[0]), random.randint(0, size[1]))
            #結束點
            end = (random.randint(0, size[0]), random.randint(0, size[1]))
            draw.line([begin, end], fill=(0, 0, 0))

    def create_points():
        '''繪製干擾點'''
        chance = min(100, max(0, int(point_chance))) # 大小限制在[0, 100]

        for w in range(width):
            for h in range(height):
                tmp = random.randint(0, 100)
                if tmp > 100 - chance:
                    draw.point((w, h), fill=(0, 0, 0))

    def create_strs():
        '''繪製驗證碼字元'''
        c_chars = get_chars()
        strs = ' %s ' % ' '.join(c_chars) # 每個字元前後以空格隔開

        font = ImageFont.truetype(font_type, font_size)
        font_width, font_height = font.getsize(strs)

        draw.text(((width - font_width) / 3, (height - font_height) / 3),
                    strs, font=font, fill=fg_color)

        return ''.join(c_chars)

    if draw_lines:
        create_lines()
    if draw_points:
        create_points()
    strs = create_strs()

    # 圖形扭曲引數
    params = [1 - float(random.randint(1, 2)) / 100,
              0,
              0,
              0,
- float(random.randint(1, 10)) / 100,
              float(random.randint(1, 2)) / 500,
              0.001,
              float(random.randint(1, 2)) / 500
              ]
    img = img.transform(size, Image.PERSPECTIVE, params) # 建立扭曲

    img = img.filter(ImageFilter.EDGE_ENHANCE_MORE) # 濾鏡,邊界加強(閾值更大)

    return img, strs  #返回驗證碼圖片,和字串型別驗證碼

驗證碼圖片生成外掛py使用方法

在驗證碼HTML的,img標籤的src圖片地址,路由對映的邏輯處理函式裡使用

首先在要顯示驗證碼圖片的html,img標籤的src="/yanzhma",一個路由對映路徑

html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>請登入</h1>
    <form method="post" action="/dlu">
        使用者名稱<input type="text" name="yhm"/><br/><br/>
        密碼<input type="text" name="mim"/><br/><br/>
        驗證碼<input type="text" name="yanzhma"/><br/><br/>
        <img src="/yanzhma"><br/><br/>
        <input type="submit" value="提交"/>
    </form>
</body>
</html>

在框架引擎,配置這個驗證碼圖片src路由對映路徑,和邏輯處理函式

src路由對映路徑的邏輯處理函式裡使用驗證碼圖片生成外掛

需要匯入io模組,和,生成驗證碼圖片外掛py

框架引擎

#!/usr/bin/env python
#coding:utf-8

import tornado.ioloop
import tornado.web                              #匯入tornado模組下的web檔案
import session_lei                              #匯入session模組


class dluHandler(tornado.web.RequestHandler):
    def get(self):
        self.render("dlu.html")  #開啟登入頁面
    def post(self):
        yhm = self.get_argument('yhm')               #接收使用者提交的使用者名稱
        mim = self.get_argument('mim')               #接收使用者提交的密碼

class yanzhmaHandler(tornado.web.RequestHandler):
    def get(self):
        #生成圖片並且返回
        import io                                       #匯入io模組
        import check_code                               #匯入驗證碼圖片生成外掛
        mstream = io.BytesIO()                          #建立一個BytesIO臨時儲存生成圖片資料
        img,code = check_code.create_validate_code()    #執行圖片生成插進裡的check_code.create_validate_code類,返回驗證碼圖片生成資料,和字串驗證碼
        img.save(mstream,"PNG")                         #將返回的驗證碼圖片資料,新增到BytesIO臨時儲存
        self.write(mstream.getvalue())                  #從BytesIO臨時儲存,獲取圖片返回給img的 src= 進行顯示

settings = {                                        #html檔案歸類配置,設定一個字典
    "template_path":"views",                     #鍵為template_path固定的,值為要存放HTML的資料夾名稱
    "static_path":"statics",                         #鍵為static_path固定的,值為要存放js和css的資料夾名稱
}

#路由對映
application = tornado.web.Application([         #建立一個變數等於tornado.web下的Application方法
    (r"/dlu", dluHandler),
    (r"/yanzhma", yanzhmaHandler),
],**settings)                                   #將html檔案歸類配置字典,寫在路由對映的第二個引數裡

if __name__ == "__main__":
    #內部socket執行起來
    application.listen(8888)                    #設定埠
    tornado.ioloop.IOLoop.instance().start()

利用js實現,點選圖片重新整理驗證碼,也就是點選一下發送一次驗證碼請求

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>請登入</h1>
    <form method="post" action="/dlu">
        使用者名稱<input type="text" name="yhm"/><br/><br/>
        密碼<input type="text" name="mim"/><br/><br/>
        驗證碼<input type="text" name="yanzhma"/><br/><br/>
        <img src="/yanzhma" onclick='ChangeCode();' id='imgCode'><br/><br/>
        <input type="submit" value="提交"/>
    </form>
    <script type="text/javascript">

        function ChangeCode() {
            var code = document.getElementById('imgCode');
            code.src += '?';
        }
    </script>

</body>
</html>

第二、驗證碼結合Session驗證

也就是在匯入Session模組,將字串驗證碼寫入使用者的Session裡,然後判斷使用者輸入的驗證碼和Session裡的驗證碼是否一致

#!/usr/bin/env python
#coding:utf-8

import tornado.ioloop
import tornado.web                                              #匯入tornado模組下的web檔案
import session_lei                                              #匯入session模組

class indexHandler(tornado.web.RequestHandler):
    def get(self):
        session = session_lei.Session(self, 1)                  #建立session物件,cookie保留1天
        zhuangti = session['zhuangtai']                         #獲取使用者cookie對應字典裡的zhuangtai
        if zhuangti == True:                                    #判斷zhuangtai是否等於True
            self.render("index.html")                           #說明登陸了顯示檢視頁
        else:
            self.redirect('/dlu')                               #跳轉登入頁

class dluHandler(tornado.web.RequestHandler):
    def get(self):
        session = session_lei.Session(self, 1)                  #建立session物件,cookie保留1天
        zhuangti = session['zhuangtai']                         #獲取使用者cookie對應字典裡的zhuangtai
        if zhuangti == True:                                    #判斷zhuangtai是否等於True
            self.redirect("/index")                             #說明登陸了跳轉檢視頁
        else:
            self.render("dlu.html",tishi = '')                      #開啟登入頁面
    def post(self):
        yhm = self.get_argument('yhm')                          #接收使用者提交的使用者名稱
        mim = self.get_argument('mim')                          #接收使用者提交的密碼
        if yhm == "admin" and mim == "admin":                   #判斷使用者名稱和密碼
            session = session_lei.Session(self, 1)              # 建立session物件,cookie保留1天
            session['yhm'] = yhm                                # 將使用者名稱儲存到session
            session['mim'] = mim                                # 將密碼儲存到session
            session['zhuangtai'] = True                         # 在session寫入登入狀態
            shur_yzhm = self.get_argument('yanzhma').upper()    #獲取使用者輸入驗證碼,轉換成大寫
            session_yzhm = session['yanzhma'].upper()           #獲取session裡的驗證碼,轉換成大寫
            if shur_yzhm == session_yzhm:                       #判斷使用者輸入的驗證碼,和session裡的驗證碼是否一致
                self.redirect("/index")                         #跳轉檢視頁
            else:
                self.render("dlu.html", tishi="驗證碼不正確")
        else:
            self.render("dlu.html",tishi = "使用者名稱或密碼不正確")

class yanzhmaHandler(tornado.web.RequestHandler):
    def get(self):
        #生成圖片並且返回
        import io                                       #匯入io模組
        import check_code                               #匯入驗證碼圖片生成外掛
        mstream = io.BytesIO()                          #建立一個BytesIO臨時儲存生成圖片資料
        img,code = check_code.create_validate_code()    #執行圖片生成插進裡的check_code.create_validate_code類,返回驗證碼圖片生成資料,和字串驗證碼
        img.save(mstream,"PNG")                         #將返回的驗證碼圖片資料,新增到BytesIO臨時儲存
        self.write(mstream.getvalue())                  #從BytesIO臨時儲存,獲取圖片返回給img的 src= 進行顯示
        session = session_lei.Session(self, 1)          # 建立session物件,cookie保留1天
        session['yanzhma'] = code                       #將字串驗證碼新增到session裡

settings = {                                            #html檔案歸類配置,設定一個字典
    "template_path":"views",                            #鍵為template_path固定的,值為要存放HTML的資料夾名稱
    "static_path":"statics",                            #鍵為static_path固定的,值為要存放js和css的資料夾名稱
}

#路由對映
application = tornado.web.Application([                 #建立一個變數等於tornado.web下的Application方法
    (r"/dlu", dluHandler),
    (r"/yanzhma", yanzhmaHandler),
    (r"/index", indexHandler),
],**settings)                                           #將html檔案歸類配置字典,寫在路由對映的第二個引數裡

if __name__ == "__main__":
    #內部socket執行起來
    application.listen(8888)                            #設定埠
    tornado.ioloop.IOLoop.instance().start()

原文轉自:http://www.cnblogs.com/adc8868/p/6902829.html