コードはDjangoの実装します

1.ジャンゴ・シンプル・キャプチャモジュール

  1. インストール django-simple-captcha
pip install django-simple-captcha
pip install Pillow
  1. 登録

そして、同じアプリを登録し、キャプチャも登録する必要がsettingsで。そしてそれはまた、それはまた、必要なデータの同期で、独自のデータテーブルを作成します。

# settings.py
INSTALLED_APPS = [
    ...
    'captcha',
]

# 执行命令进行数据迁徙,会发现数据库中多了一个 captcha_captchastore 的数据表
python manage.py migrate
  1. ルートの追加

プロジェクトのルートディレクトリの下にurls.py追加するにはcaptcha、対応するルーティング:

from django.contrib import admin
from django.urls import path, include


urlpatterns = [
    path('admin/', admin.site.urls),
    path('captcha', include('captcha.urls')),        # 验证码
]
  1. フォームフォームを変更

Djangoは通常、フォーム形式で生成され、一般的に認証コード登録ログインフォームを伴うので、する必要があるforms.pyフィールド検証コードを追加します。

from django import forms
from captcha.fields import CaptchaField     # 一定要导入这行


class UserForm(forms.Form):
    username = forms.CharField(
        label='用户名',                # 在表单里表现为 label 标签
        max_length=128,
        widget=forms.TextInput(attrs={'class': 'form-control'})   # 添加 css 属性
    )

    captcha = CaptchaField(
        label='验证码',
        required=True,
        error_messages={
            'required': '验证码不能为空'
        }
    )
  1. ビュー機能:
from django.shortcuts import render
from app.forms import UserForm


def home(request):
    register_form = UserForm(request.POST)
    if register_form.is_valid():
        pass
    register_form = UserForm()
    return render(request, 'index.html', {'register_form': register_form})
  1. フロントエンドレンダリング

次のステップでは、フロントエンドをレンダリングする方法です。

<html>
    <head></head>
    <body>
        <form action='#' method='post'>
            {{ register_form.captcha.label_tag }}
            {{ register_form.captcha }} {{ 
        </form>
    </body>
</html>

限り

2.手動で生成されたコード

主な用途は、モジュール描画されるPILとランダムモジュールをrandomバックグラウンドで乱数と画像列を生成するために、次にメモリに記憶されている(また、Djangoプロジェクトに直接格納することができます)。

指定のフロントエンドでimg発生パス検証コード:タグ、src属性パス<img src='/accounts/check_code/'

  1. ペイントプログラム check_code.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))

# PIL

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="static/font/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,
              1 - 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

ヒント

ここでは、指定する必要がありMonaco.ttf、フォントを:

font_type="static/font/Monaco.ttf",

# https://pan.baidu.com/s/1XwyaFC_MROFA4fXujVwH3A 提取码:17f8 
  1. ビュー機能 views.py
from django.shortcuts import render, redirect, HttpResponse
from blog.check_code import create_validate_code
from io import BytesIO
from django.contrib import auth
from django.http import JsonResponse


def check_code(request):
    """
    获取验证码
    :param request:
    :return:
    """
    stream = BytesIO()
    # 生成图片 img、数字代码 code,保存在内存中,而不是 Django 项目中
    img, code = create_validate_code()
    img.save(stream, 'PNG')

    # 写入 session
    request.session['valid_code'] = code
    print(code)
    return HttpResponse(stream.getvalue())


def login(request):
    """
    登录视图
    :param request:
    :return:
    """
    if request.method == 'POST':
        ret = {'status': False, 'message': None}
        username = request.POST.get('username')
        password = request.POST.get('password')

        # 获取用户输入的验证码
        code = request.POST.get('check_code')
        p = request.POST.get('p')


        # 用户输入的验证码与 session 中取出的验证码比较
        if code.upper() == request.session.get('valid_code').upper():
            # 验证码正确,验证用户名密码是否正确
            user_obj = auth.authenticate(username=username, password=password)
            if user_obj:
                # 验证通过,则进行登录操作
                # 封装到 request.user 中
                auth.login(request, user_obj)
                return redirect('accounts:home')
            else:
                ret['status'] = True
                ret['message'] = '用户名或密码错误'
                return render(request, 'accounts/login.html', ret)
        else:
            ret['status'] = True
            ret['message'] = '验证码错误'
        return render(request, 'accounts/login.html', ret)

    return render(request, 'accounts/login.html')
  1. ログインページ login.html
{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.css' %}">
    <style>
        .login-col {
            margin-top: 100px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="well col-md-6 col-md-offset-3 login-col">
            <h3 class="text-center">登录</h3>

            <!--错误信息-->
            {% if status %}
                <div class="alert alert-danger" role="alert">
                    <p id="login-error">{{ message }}</p>
                    <p id="login-error"></p>
                </div>
            {% endif %}

            <form action="{% url 'accounts:login' %}" method="post" novalidate>
                {% csrf_token %}
                <div class="form-group">
                    <label for="exampleInputUsername">用户名:</label>
                    <input type="text" class="form-control" id="exampleInputUsername" placeholder="用户名" name="username">
                </div>

                <div class="form-group">
                    <label for="exampleInputPassword1">密码:</label>
                    <input type="password" class="form-control" id="exampleInputPassword" placeholder="密码"
                           name="password">
                </div>

                <!--验证码-->
                <div class="form-group">
                    <label for="id_code">验证码:</label>
                    <div class="row">
                        <div class="col-md-7 col-xs-7">
                            <input type="text" class="form-control" id="id_code" placeholder="请输入验证码" name="check_code">
                        </div>

                        <div class="col-md-5 col-xs-5">
                            <img src="/accounts/check_code" onclick="changeImg(this)" class="img">
                        </div>
                    </div>
                </div>


                <div class="checkbox">
                    <label>
                        <input type="checkbox"> 记住我
                    </label>
                </div>
                <button type="submit" class="btn btn-primary btn-block" id="login-button">提交</button>
            </form>
        </div>
    </div>
</div>

<script src="{% static 'js/jquery-3.1.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.js' %}"></script>

<script>
    function changeImg(ths) {
        // 硬编码
        ths.src = '/accounts/check_code/?temp=' + Math.random();

        // 使用命名空间,发送请求
        // ths.src = '{% url 'accounts:check_code' %}' + '?temp=' + Math.random();

    }

</script>

</body>
</html>

キャプチャ用にimgラベルバインディングonclickイベント、ユーザーが同等のアクセスで確認コードを、クリックしたときhttp://127.0.0.1:8000/accounts/check_code/?temp=一个随机数、すなわちhttp://127.0.0.1:8000/accounts/check_code/GETリクエストを送信、再度、確認コードを生成し、バックグラウンドから復帰します。

  1. ルーティング accounts/urls.py
from django.urls import path
from accounts import views

app_name = 'accounts'
urlpatterns = [
    # 登录
    path('login/', views.login, name='login'),      

    # 获取验证码
    path('check_code/', views.check_code, name='check_code'),

    # 首页
    path('home/', views.home, name='home'),

    # 注销
    path('logout/', views.logout, name='logout'),
]

ヒント

  • ペイントcheck_code.py機能をインポートする必要性を考慮して、アイテム上の任意の場所に保存されました。
  • Monaco.ttf必要不可欠なフォントは、静的なドキュメントに配置することができますが、変更する必要があるcheck_code.pyフォントパスが導入されます。
  • ユーザーを検証単に削除し、その比較にセッションコードから生成され、PINが正しい入りました。
  • セキュリティコードの更新は、その後、ちょうどそれが取得するための要求を送信してみましょう。

スライドポールテストコードの3テクノロジー

上記の二つの絵の検証コードに加えて、より多く持って使用されるスライドのコードがあり、非常に検査技術を

  1. 公式のダウンロード元、およびインストールgeetestモジュールを

公式サイト

公式ウェブサイトをご覧ください、選択します。資料-動作検証-展開するサーバーを選択するPython-直接のgitを使用したり、ダウンロードしgt3-python-sdkたファイルを。

pip install geetest
pip install requests    # 有可能还需要 requests 模块

<!-- 引入封装了failback的接口--initGeetest -->
<script src="http://static.geetest.com/static/tools/gt.js"></script>
  1. ログインページ login2.html

HTML部分

{% load static %}
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>登录</title>
    <link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.css' %}">
    <style>
        .login-col {
            margin-top: 100px;
        }
    </style>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="well col-md-6 col-md-offset-3 login-col">
            <h3 class="text-center">登录</h3>
            <form>
                {% csrf_token %}
                <div class="form-group">
                    <label for="username">用户名:</label>
                    <input type="text" class="form-control" id="username" placeholder="用户名" name="username">
                </div>

                <div class="form-group">
                    <label for="password">密码:</label>
                    <input type="password" class="form-control" id="password" placeholder="密码" name="password">
                </div>


                <!--极验科技滑动验证码-->
                <div class="form-group">
                    <!-- 放置极验的滑动验证码 -->
                    <div id="popup-captcha"></div>
                </div>

                <!--记住我-->
                <div class="checkbox">
                    <label>
                        <input type="checkbox"> 记住我
                    </label>
                </div>

                <!--登录按钮-->
                <button type="button" class="btn btn-primary btn-block" id="login-button">提交</button>

                <!--错误信息-->
                <span class="login-error"></span>
            </form>
        </div>
    </div>
</div>
</body>
</html>

JavaScriptのセクション

<script src="{% static 'js/jquery-3.3.1.js' %}"></script>
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.js' %}"></script>
<!-- 引入封装了failback的接口--initGeetest -->
<script src="http://static.geetest.com/static/tools/gt.js"></script>


<script>
    var handlerPopup = function (captchaObj) {
        // 成功的回调
        captchaObj.onSuccess(function () {
            var validate = captchaObj.getValidate();
            var username = $('#username').val();
            var password = $('#password').val();
            console.log(username, password);
            $.ajax({
                url: "/accounts/login2/", // 进行二次验证
                type: "post",
                dataType: 'json',
                data: {
                    username: username,
                    password: password,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val(),
                    geetest_challenge: validate.geetest_challenge,
                    geetest_validate: validate.geetest_validate,
                    geetest_seccode: validate.geetest_seccode
                },
                success: function (data) {
                    console.log(data);
                    if (data.status) {
                        // 有错误,在页面上显示
                        $('.login-error').text(data.msg);
                    } else {
                        // 登录成功
                        location.href = data.msg;
                    }
                }
            });
        });

        // 当点击登录按钮时,弹出滑动验证码窗口
        $("#login-button").click(function () {
            captchaObj.show();
        });

        // 将验证码加到id为captcha的元素里
        captchaObj.appendTo("#popup-captcha");
        // 更多接口参考:http://www.geetest.com/install/sections/idx-client-sdk.html
    };

    $('#username, #password').focus(function () {
        // 将之前的错误清空
        $('.login-error').text('');
    });

    // 验证开始需要向网站主后台获取id,challenge,success(是否启用failback)
    $.ajax({
        url: "/accounts/pc-geetest/register?t=" + (new Date()).getTime(), // 加随机数防止缓存
        type: "get",
        dataType: "json",
        success: function (data) {
            // 使用initGeetest接口
            // 参数1:配置参数
            // 参数2:回调,回调的第一个参数验证码对象,之后可以使用它做appendTo之类的事件
            initGeetest({
                gt: data.gt,
                challenge: data.challenge,
                product: "popup", // 产品形式,包括:float,embed,popup。注意只对PC版验证码有效
                offline: !data.success // 表示用户后台检测极验服务器是否宕机,一般不需要关注
                // 更多配置参数请参见:http://www.geetest.com/install/sections/idx-client-sdk.html#config
            }, handlerPopup);
        }
    });

</script>

JSコードはバックグラウンドにAjaxリクエストを送信し、最初の値の値の形態を得ることである二つの部分に分割され、ユーザ名とパスワードが正しいことを確認するために、エラーは、エラーメッセージ場合に表示されます。背景にパラメータを必要なコードの第2の部分を得ます。

  1. ビュー機能 views.py
from django.shortcuts import render, redirect, HttpResponse
from django.http import JsonResponse
from geetest import GeetestLib


def login2(request):
    if request.method == 'POST':
        ret = {'status': False, 'msg': None}
        username = request.POST.get('username')
        password = request.POST.get('password')

        print(username, password)

        # 获取极验,滑动验证码相关参数
        gt = GeetestLib(pc_geetest_id, pc_geetest_key)
        challenge = request.POST.get(gt.FN_CHALLENGE, '')
        validate = request.POST.get(gt.FN_VALIDATE, '')
        seccode = request.POST.get(gt.FN_SECCODE, '')
        status = request.session[gt.GT_STATUS_SESSION_KEY]
        user_id = request.session["user_id"]

        print(gt, challenge, validate, seccode, status)

        if status:
            result = gt.success_validate(challenge, validate, seccode, user_id)
        else:
            result = gt.failback_validate(challenge, validate, seccode)
        if result:
            # 验证码正确
            # 利用auth模块做用户名和密码的校验
            user_obj = auth.authenticate(username=username, password=password)
            if user_obj:
                # 用户名密码正确
                # 给用户做登录
                auth.login(request, user_obj)
                ret["msg"] = "/accounts/home/"
                # return redirect('accounts:home')
            else:
                # 用户名密码错误
                ret["status"] = True
                ret["msg"] = "用户名或密码错误!"
        else:
            ret["status"] = True
            ret["msg"] = "验证码错误"

        return JsonResponse(ret)
    return render(request, "accounts/login2.html")

# 请在官网申请ID使用,示例ID不可使用
pc_geetest_id = "b46d1900d0a894591916ea94ea91bd2c"
pc_geetest_key = "36fc3fe98530eea08dfc6ce76e3d24c4"

# 处理极验 获取验证码的视图
def get_geetest(request):
    user_id = 'test'
    gt = GeetestLib(pc_geetest_id, pc_geetest_key)
    status = gt.pre_process(user_id)
    request.session[gt.GT_STATUS_SESSION_KEY] = status
    request.session["user_id"] = user_id
    response_str = gt.get_response_str()
    return HttpResponse(response_str)
  1. ルーティング accounts/urls.py
from django.urls import path
from accounts import views

app_name = 'accounts'
urlpatterns = [
    path('home/', views.home, name='home'),
 
    # 极验滑动验证码 获取验证码的url
    path('pc-geetest/register/', views.get_geetest, name='get_geetest'),

    path('login2/', views.login2, name='login2'),
]

概要

  • 後方ポールジャンゴを支持することに加えてコードをスライドは、フラスコ、竜巻などサポート
  • 上記ポストは、Ajaxリクエストの形式で送信され、そうcsrf_tokenかどうかを確認するために注意を払う、とボタンを提出buttonする必要がありますタイプを提出するbuttonのではなくsubmit(段付き孔)
  • また、など、より多くの例を組み込み、携帯端末を持っている、公式のダウンロード元を参照してください。

おすすめ

転載: www.cnblogs.com/midworld/p/10992019.html