基於django實現圖文驗證碼兩種方式


引言:無論做什么項目用戶模塊永遠繞不開的坎,而用戶模塊貌似一定是有驗證碼的,這里介紹python下兩種實現驗證碼的方式
環境介紹:django+python3.6以上版本

方式1:使用django自帶的django-simple-captcha

  • 第三方包的下載

    pip install django-simple-captcha
    
  • 將captcha安裝到 install_apps里面

    INSTALLED_APPS = [
        'django.contrib.admin',
        'django.contrib.auth',
        'django.contrib.contenttypes',
        'django.contrib.sessions',
        'django.contrib.messages',
        'django.contrib.staticfiles',
        'captcha',
    ]
    
  • 在主路由配置captcha應用的路由

    urlpatterns = [
        path('admin/', admin.site.urls),
        path('captcha/',include('captcha.urls')),
    ]
    
    
  • 遷移同步,生成captcha所依賴的表

    #生成遷移腳本
    python manage.py makemigrations
    #執行文件遷移
    python manage.py migerte
    '''
    如果出現錯誤可以嘗試執行執行第二條命令,或者在兩條命令后加上app名
    python manage.py makemigrations captcha
    python manage.py migerte captcha
    '''
    
  • 將captcha字段在form類當中進行設置

    #例子:forms.py
    from django import forms
    from captcha.fields import CaptchaField
    
    class UserRegisterForm(forms.Form):
        email = forms.EmailField(required=True)
        password = forms.CharField(required=True,min_length=6,max_length=26,error_messages={
            'required':'密碼不能為空',
            'min_length': '密碼至少6個字符',
            'max_length' : '密碼過長',
        })
        captcha = CaptchaField()
    
  • 在后台邏輯當中,get請求里面實例化我們的form,將form對象返回到頁面

    #views.py 代碼邏輯
    def user_register(request):
        if request.method == 'GET':
            #實例化user_register_form 不是為了驗證,而是為了使用驗證碼
            user_register_form = UserRegisterForm()
    
            return render(request,'register.html',{'user_register_form':user_register_form})
        else:
            pass
    
  • 在頁面上 獲取驗證碼以下是注冊頁中部分代碼

    <div class="form-group marb8 captcha1 ">
         <label>驗&nbsp;證&nbsp;碼</label>
         {{ user_register_form.captcha }}
    </dv>
    
  • 打開注冊頁面發送get請求得到需要的效果,且點擊會刷新驗證碼

方式2:自己動手豐衣足食,自己畫驗證碼

python為我們提供了額外的第三方畫圖庫

使用須知

  • 熟練使用django框架
  • 熟練使用html超文本標記語言
  • 會使用ajax配置后台邏輯

實現原理

  • 通過PIL繪制圖片(可定義字符,圖片大小,辨別障礙...)
  • 前端展示圖片
  • 用戶提交驗證碼,通過ajax將信息發送至前台進行對比
  • 點擊圖片刷新(通過傳遞不同的數據來展示不同的圖片)

不多BB直接上代碼

#views.py
#views
from PIL import Image, ImageDraw, ImageFont
from random

def verify_code(request):
    # 引入隨機函數模塊
    import random
    def rndColor():
        """
        生成隨機顏色
        :return:
        """
        return (random.randint(0, 255), random.randint(10, 255), random.randint(64, 255))

    # 定義變量,用於畫面的背景色、寬、高
    bgcolor = (rndColor())
    width = 100
    height = 37
    # 創建畫面對象
    im = Image.new('RGB', (width, height), bgcolor)
    # 創建畫筆對象
    draw = ImageDraw.Draw(im)
    # 調用畫筆的point()函數繪制噪點
    for i in range(0, 100):
        xy = (random.randrange(0, width), random.randrange(0, height))
        fill = (random.randrange(0, 255), 255, random.randrange(0, 255))
        draw.point(xy, fill=fill)
    # 定義驗證碼的備選值
    str1 = 'ABCD123EFGHIJK456LMNOPQRS789TUVWXYZ0'
    # 隨機選取4個值作為驗證碼
    rand_str = ''
    for i in range(0, 4):
        rand_str += str1[random.randrange(0, len(str1))]
    # 構造字體對象,ubuntu的字體路徑為“/usr/share/fonts/truetype/freefont”
    font = ImageFont.truetype('simhei.ttf', 23)
    # 構造字體顏色
    fontcolor = (255, random.randrange(0, 255), random.randrange(0, 255))
    # 繪制4個字
    draw.text((5, 2), rand_str[0], font=font, fill=fontcolor)
    draw.text((25, 2), rand_str[1], font=font, fill=fontcolor)
    draw.text((50, 2), rand_str[2], font=font, fill=fontcolor)
    draw.text((75, 2), rand_str[3], font=font, fill=fontcolor)

    # 寫干擾圓圈
    for i in range(40):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=rndColor())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=rndColor())
    # 畫干擾線
    for i in range(5):
        x1 = random.randint(0, width)
        y1 = random.randint(0, height)
        x2 = random.randint(0, width)
        y2 = random.randint(0, height)
        draw.line((x1, y1, x2, y2), fill=rndColor())
    # 釋放畫筆
    del draw
    # 存入session,用於做進一步驗證
    request.session['verifycode'] = rand_str
    # 內存文件操作
    buf = BytesIO()
    # 將圖片保存在內存中,文件類型為png
    im.save(buf, 'png')
    # 將內存中的圖片數據返回給客戶端,MIME類型為圖片png
    return HttpResponse(buf.getvalue(), 'image/png')

#將驗證碼的數據其實是存儲到session中通過session和前端獲取的值進行比較
#因為要忽視大小寫,這里用.lower(),全部轉換為小寫進行比較
def verify_yz(request):
    '''驗證碼校驗視圖'''

    user_yzm = request.GET.get('user_yzm')

    verifycode = request.session['verifycode']

    print('user_yzm='+user_yzm)
    print('verifycode='+verifycode)
    if user_yzm.lower() == verifycode.lower():
        return restful.ok("OK", data=None)
    else:
        return restful.params_error("驗證碼錯誤", data=None)

#html

#輸入驗證碼
<input type="text" name="user_yzm" id='user_yzm' class="user_yzm" placeholder="請輸入圖文驗證">
#盒子內放置圖片
<div id="photo_yzm">
    <img id="yzm" class="yzm" src="/user/verify_code"/>//也可以寫成:src="{% url 'user:verify_code' %}"
</div>
#實現點擊驗證碼圖片進行刷新的js代碼
<script type="text/javascript" src="{% static 'js/jquery-1.12.4.min.js'%}"></script>
	<script type="text/javascript" src="{% static 'js/register.js' %}"></script>
//ajax
<script>
        $(function(){
            
            var img = $('#yzm');
            //點擊圖片觸發事件
            img.click(function(){
			//獲取現在時間,用於每次刷新圖片不同
             mydate=new Date();
             //點擊卻換yzm的src屬性.后面加參數是因為每次訪問網站之后每次參數不同接收到的圖像也不同,如果沒有傳參數,每次返回的都是相同的圖像
             $(this).attr("src",'/user/verify_code?a='+mydate);
            });// img click
		
            var photo_text = $('.user_yzm');
			//驗證碼圖片改變事件
            photo_text.change(function(){
                //ajax
                var user_yzm = $(this).val();
                {#alert(user_yzm);#}
                $.ajax({
                    //獲取方式,這邊寫get,views獲取也要寫get,所連接到的是本文views中71行,使用POST出現問題請看:https://blog.csdn.net/weixin_43790705/article/details/87867172
                    type: "get",
                    //將數據發送到:
                    url: "{% url 'user:verify_yz' %}",
                    //數據
                    data:"user_yzm="+user_yzm,
                    //數據類型默認為json
                    success: function(msg){
                    {#alert('發送ajax');#}
                    {#obj = eval("("+msg+")");#}
                    alert(msg.code);
					//如果返回的參數的code屬性為200那么執行:
                    if(msg.code=='200'){
                         $('#user_yzm').css({"background": "rgba(87,255,53,0.51)"});
                        }
                     //否則
                     else{

                        $('#user_yzm').css({"background": "rgba(255,113,103,0.47)"});
                        }
                }
                })// ajax

            }) //change

        })// $func

    </script>


免責聲明!

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



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