Django使用Django Simple Captcha实现登录验证码

一.Django Simple Captcha的安装与配置

  • 安装:
pip3 install django-simple-captcha
  • 配置:
    在settings.py中需要配置INSTALLED_APPS、TEMPLATES和DATABASES:
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'user',
    # 添加验证码功能
    'captcha',
]

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')],
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
        },
    },
]

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}
  • 验证码功能配置
    Django Simple Captcha设有多种验证码的生成方式,如设置验证码的内容、图片噪点和图片大小等,这些功能可以在(site-packages\captcha\cong\settings.py)中的源码内自行查看。
    以下只是举例:
"""
MyDjango的settings.py
Django Simple Captcha的基本配置
设置验证码的显示顺序
一个验证码识别包含文本输入框,隐藏域和验证码图片
"""
# CAPTCHA_OUTPUT_FORMAT是设设置三者的显示顺序
CAPTCHA_OUTPUT_FORMAT = '%(text_field)s %(hidden_field)s %(image)s'
# 设置图片噪点
CAPTCHA_NOISE_FUNCTIONS = (
    # 设置样式
    'captcha.helpers.noise_null',
    # 设置干扰线
    'captcha.helpers.noise_arcs',
    # 设置干扰点
    'captcha.helpers.noise_dots',
)

# 图片大小
CAPTCHA_IMAGE_SIZE = (100, 25)
# 设置图片背景颜色
CAPTCHA_BACKGROUND_COLOR = '#ffffff'
# 图片中的文字为随机英文字母
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
# 图片中的文字为英文单词
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.word_challenge'
# 图片中的文字为数字表达式
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
# 设置字符个数
CAPTCHA_LENGTH = 4
# 设置超时时间(minutes)
CAPTCHA_TIMEOUT = 1
  • 完成上述配置后,下一步执行数据迁移,因为验证码需要依赖数据表才能实现

二.使用验证码实现用户登录

完成Django Simple Captcha与MyDjango的功能搭建,下一步在用户登录页面实现验证码功能。

  • 用户登录页面:由表单生成,表单类在项目应用user的forms.py中定义。
  • 登录验证:触发POST请求,用户信息以及验证功能由Django内置的Auth认证系统实现。
  • 验证码动态刷新:由Ajax向Captcha功能应用发送GET请求完成动态刷新。
  • 验证码动态验证:由Ajax向Django发送GET请求完成验证码验证。
# user的forms.py
# 定义用户登录表单类
from django import forms
from captcha.fields import CaptchaField
class CaptchaTestForm(forms.Form):
    username = forms.CharField(label='用户名')
    password = forms.CharField(label='密码', widget=forms.PasswordInput)
    captcha = CaptchaField()

#MyDjango的urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include(('user.urls', 'user'), namespace='user')),
    path('captcha/', include('captcha.urls'))
]
# user的urls.py
from django.urls import path
from .views import *

urlpatterns = [
    # 用户登录界面
    path('', loginView, name='login'),
    path('ajax_val', ajax_val, name='ajax_val'),
]
# user的views.py
from django.shortcuts import render
from django.contrib.auth.models import User
from django.contrib.auth import login, authenticate
from .forms import CaptchaTestForm


# 用户登录
def loginView(request):
    if request.method == 'POST':
        form = CaptchaTestForm(request.POST)
        # 验证表单数据
        if form.is_valid():
            u = form.cleaned_data['username']
            p = form.changed_data['password']
            if User.objects.filter(username=u):
                user = authenticate(usernme=u, password=p)
                if user:
                    if user.is_active:
                        login(request, user)
                        tips = '登陆成功'
                else:
                    tips = '账号密码错误,请重新输入'
            else:
                tips = '用户名不存在,请注册'
    else:
        form = CaptchaTestForm()
    return render(request, 'user.html', locals())


# ajax接口,实现动态验证码验证
from django.http import JsonResponse
from captcha.models import CaptchaStore


def ajax_val(request):
    if request.is_ajax():
        # 用户输入的验证码结果
        r = request.GET['response']
        # 隐藏域的value值
        h = request.GET['hashkey']
        cs = CaptchaStore.objects.filter(response=r, hashkey=h)
        # 若存在cs,则验证成功,否则验证失败
        if cs:
            json_data = {'status': 1}
        else:
            json_data = {'status': 0}
        return JsonResponse(json_data)
    else:
        json_data = {'status': 0}
        return JsonResponse(json_data)
# templates的user.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Django</title>
    <script src="http://apps.bdimg.com/libs/jquery/2.1.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://unpkg.com/mobi.css/dist/mobi.min.css">
</head>
<body>
<div class="flex-center">
<div class="container">
<div class="flex-center">
<div class="unit-1-2 unit-1-on-mobile">
    <h1>MyDjango Verification</h1>
    {% if tips %}
    <div>{{ tips }}</div>
    {% endif %}
    <form class="form" action="" method="post">
        {% csrf_token %}
        <div>用户名:{{ form.username }}</div>
        <div>密码:{{ form.password }}</div>
        <div>验证码:{{ form.captcha }}</div>
        <button type="submit" class="btn btn-primary btn-block">确定</button>
    </form>
</div>
</div>
</div>
</div>
<script>
    $(function () {
        // ajax 刷新验证码
        $('.captcha').click(function () {
        console.log('click');
        $.getJSON("/captcha/refresh",function (result) {
            $('.captcha').attr('src', result['image_url']);
            $('#id_captcha_0').val(result['key'])
        });
        });
        // ajax动态验证验证码
        $('#id_captcha_1').blur(function () {
            // #id_captcha_1 为输入框的id
            // 该输入法失去焦点就会触发函数
            json_data = {
                // 获取输入框和影藏字段id_captcha_0的数值
                'response':$('#id_captcha_1').val(),
                'hashkey':$('#id_captcha_0').val()
            }
        $.getJSON('/ajax_val', json_data,function (data) {
            $('#captcha_status').remove()
            // 若status返回1,则验证码正确
            // 若status返回0,则验证码错误
            if(data['status']){
                $('#id_captcha_1').after('<span id="captcha_status">*验证码正确</span>')
            }else{
                $('#id_captcha_1').after('<span id="captcha_status">*验证码错误</span>')
            }
        });
        });
    })
</script>
</body>
</html>

至此,运行MyDjango,访问127.0.0.1:8000即可看到带验证码的用户登录页面。单击图片验证码将触发Ajax请求,Django动态刷新验证码图片,并在数据表captcha_captchastore中创建验证码信息。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,937评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,503评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,712评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,668评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,677评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,601评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,975评论 3 396
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,637评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,881评论 1 298
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,621评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,710评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,387评论 4 319
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,971评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,947评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,189评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,805评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,449评论 2 342