WEB開發-動態驗證碼


1.基於Python實現,用到了django后台處理,刷新驗證碼功能,其他語言大同小異

 

 


2.登錄界面

login.html

<!DOCTYPE html>
<html lang="en">

<head>

    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="description" content="">
    <meta name="author" content="">

    <title>DevOPS v1.0</title>

    <!-- Bootstrap Core CSS -->
    <link href="/static/vendor/bootstrap/css/bootstrap.min.css" rel="stylesheet">

    <!-- MetisMenu CSS -->
    <link href="/static/vendor/metisMenu/metisMenu.min.css" rel="stylesheet">

    <!-- Custom CSS -->
    <link href="/static/dist/css/sb-admin-2.css" rel="stylesheet">

    <!-- Custom Fonts -->
    <link href="/static/vendor/font-awesome/css/font-awesome.min.css" rel="stylesheet" type="text/css">

    <!-- HTML5 Shim and Respond.js IE8 support of HTML5 elements and media queries -->
    <!-- WARNING: Respond.js doesn't work if you view the page via file:// -->
    <!--[if lt IE 9]>
        <script src="https://oss.maxcdn.com/libs/html5shiv/3.7.0/html5shiv.js"></script>
        <script src="https://oss.maxcdn.com/libs/respond.js/1.4.2/respond.min.js"></script>
    <![endif]-->

</head>

<body>

<div class="container">
    <div class="row">
        <div class="col-md-4 col-md-offset-4">
            <div class="login-panel panel panel-default">
                <div class="panel-heading">
                    <h3 class="panel-title">Please Sign In</h3>
                </div>
                <div class="panel-body">
                    <form role="form" action="/index/login/" method="post">
                        <fieldset>
                            <div class="form-group">
                                <input class="form-control" placeholder="Username" name="username" type="text"
                                       autofocus>
                            </div>
                            <div class="form-group">
                                <input class="form-control" placeholder="Password" name="password" type="password"
                                       value="">
                            </div>
                            <div class="form-group">
                                <input class="form-control" placeholder="驗證碼" name="yanzhengma" type="text" value="">
                                {#                                    <span><img src={{ data }}></span>#}
                                {#                                    <span>{{ data }}</span>#}
                                <img src="/index/yanzhengma/" onclick="ChangeCode(this);"/>
                                <div style="color: red;">{{ msg }}</div>
                            </div>
                            <div class="checkbox">
                                <label>
                                    <input name="remember" type="checkbox" value="Remember Me">Remember Me
                                </label>
                            </div>
                            <!-- Change this to a button or input when using this as a form -->
                            {#                                <a href="/login/" class="btn btn-lg btn-success btn-block">Login</a>#}
                            <input type="submit" class="btn btn-lg btn-success btn-block" name="Login"/>
                        </fieldset>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

<!-- jQuery -->
<script src="/static/vendor/jquery/jquery.min.js"></script>

<!-- Bootstrap Core JavaScript -->
<script src="/static/vendor/bootstrap/js/bootstrap.min.js"></script>

<!-- Metis Menu Plugin JavaScript -->
<script src="/static/vendor/metisMenu/metisMenu.min.js"></script>

<!-- Custom Theme JavaScript -->
<script src="/static/dist/js/sb-admin-2.js"></script>

<script type="text/javascript">
    function ChangeCode(ths) {
 var src_re = $(ths).attr('src');
        $(ths).attr('src', src_re + '?');
    }
</script>

</body>

</html>

 

 

里面涉及到2個后端視圖函數login和get_yanzhengma

 

 


 3.后端視圖函數

helper.py

# -*- coding=utf-8 -*-
import random


# 隨機字母:
def rndChar():
    return chr(random.randint(65, 90)) + chr(random.randint(65, 90)) + chr(random.randint(65, 90)) + chr(random.randint(65, 90))

 

Django的views.py

# -*- coding=utf-8 -*-
##############################
from django.shortcuts import render, HttpResponse, render_to_response,redirect
from app import models
from helper import rndChar
from PIL import Image, ImageFont, ImageDraw
import io

# Create your views here.

def index(request):
    # return HttpResponse('123456')
    return render_to_response('app/pages/index.html')

def login(request):
    if request.method == 'POST':
        print request.POST
        username = request.POST.get('username',None)
        password = request.POST.get('password',None)
        yanzhengma = request.POST.get('yanzhengma',None)
        # print yanzhengma,request.session['yanzhengma']
        if yanzhengma.upper() != request.session['yanzhengma'].upper():
            return render_to_response('app/pages/login.html',{'msg':'驗證碼錯誤'})
        count = models.AdminInfo.objects.filter(username=username,password=password).count()
        if count > 0:
            request.session['is_login'] = {'user':username}
            return redirect('/index/')
            # return render_to_response('app/pages/index.html')
        else:
            return render_to_response('app/pages/login.html',{'msg':'賬戶密碼錯誤'})
    else:
        # print stream.getvalue()
        # im.save("static/image/t.png")
        # request.session['yanzhengma'] = text
        return render_to_response('app/pages/login.html',{'msg':''})

def yanzhengma(request):
     #text為產生的4位隨機字符串
    text = rndChar() 
    # print text
    request.session['yanzhengma'] = text
    #圖片處理程序,將文本做成圖片
    im = Image.new("RGB", (130, 35), (255, 255, 255))
    dr = ImageDraw.Draw(im)
    font = ImageFont.truetype("arial", 24)
    # simsunb.ttf 這個從windows fonts copy一個過來
    dr.text((10, 5), text, font=font, fill="#000000")
    # im.show()
    #創建一個io對象
    stream = io.BytesIO()
    #將圖片對象im保存到stream對象里
    im.save(stream, "png")
    #stream.getvalue()圖片二級制內容,再通過HttpResponse封裝,返回給前端頁面
    return HttpResponse(stream.getvalue())

 

 


4.效果圖展示

 

 


 5.備注:

(1)img標簽的src屬性,去這個/get_yanzhengma/去取圖片

(2)get_yanzhengma函數執行

(3)通過random模塊生成隨機碼,4個字母

(4)通過PIL模塊將隨機數字轉換為圖片對象im

(5)創建一個BytesIO對象,內存對象,可以存儲二進制的東西

(6)將圖片對象保存到BytesIO對象中,此處在內存里

#話說為什么要將圖片對象保存到BytesIO對象中而不是直接寫到硬盤里存為圖片文件呢?因為這樣就保證了在同一個時刻,不同用戶訪問到的驗證碼是不一樣的,而且都是存儲在內存中的。

#如果寫成驗證碼圖片文件到硬盤里,有可能B頁面顯示的驗證碼是ABCD,但是B用戶還沒提交,A用戶這會訪問,刷新了驗證碼,把驗證碼變更為DCBA了,B頁面里看到的還是ABCD,導致一直輸不對驗證碼;無法保證2個用戶的驗證碼圖片沖突問題

#后端驗證碼的隨機值是存儲在session中的,每次用戶GET請求,服務器上生成隨機驗證碼存儲在session中,並給頁面返回,如果用戶提交的驗證碼和后端session中記錄的一致通過,如果不一致,重新刷新驗證碼,用戶重新進行提交

(7)BytesIO對象的getvalue()方法返回二進制內容

(8)django提供的HttpResponse封裝二進制內容為識別的東西傳遞給前端

(7)前端img標簽正常顯示圖片

(9)用戶點擊圖片,js先獲取到這個圖片標簽,取到當前的src屬性值存為變量src_re,然后更改src的屬性值為src_re + ?

#為什么要加?呢是因為GET請求,每最后加一個?代表一個新的url,但是效果呢是和/index/yanzhengma/是一致的,每點一次,后面加一個?。/index/yanzhengma/?    /index/yanzhengma/??這個意思

#如果每次只更改src的屬性值為/index/yanzhengma/的話,不會進行request請求,會直接瀏覽器緩存讀取。達不到刷新驗證碼的目的


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM