django-simple-captcha 图形验证码使用总结

2023-02-18 11:38:41 浏览数 (1)

官方文档

  • https://django-simple-captcha.readthedocs.io/en/latest/usage.html
  • https://github.com/mbi/django-simple-captcha

基本配置

安装 captcha

pip install  django-simple-captcha

settings.py

代码语言:javascript复制
# 添加 captcha APP
INSTALLED_APPS = [
     # 添加 验证码 APP
    'captcha',

]

# Captcha 配置
# Captcha 默认格式
CAPTCHA_OUTPUT_FORMAT = '%(image)s %(text_field)s %(hidden_field)s '
CAPTCHA_NOISE_FUNCTIONS = (
    # 'captcha.helpers.noise_null',  # 没有样式
    # 'captcha.helpers.noise_arcs',  # 线
    'captcha.helpers.noise_dots',  # 点
)
# 图片中的文字为随机英文字母,如 mdsh
CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.random_char_challenge'
# 图片中的文字为数字表达式,如 2   2 =
# CAPTCHA_CHALLENGE_FUNCT = 'captcha.helpers.math_challenge'
# 超时(minutes)
CAPTCHA_TIMEOUT = 30
# 验证码输入框指定 TEMPLATE, 表单使用 CaptchaField 字段生效
CAPTCHA_TEXT_FIELD_TEMPLATE = "captcha_text_field.html"

自定义 CAPTCHA_TEXT_FIELD TEMPLATE

captcha_text_field.html(加了一个 placeholder)

代码语言:javascript复制
<input autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" id="{{id}}_1" name="{{name}}_1" type="text" placeholder="请输入验证码" />

项目 urls.py

代码语言:javascript复制
urlpatterns = [
               # 添加 captcha url
               url(r'^captcha/', include('captcha.urls')),  # django 1.11
              ]

官方用法

Adding to a Form

Using a CaptchaField is quite straight-forward:

Define the Form

To embed a CAPTCHA in your forms, simply add a CaptchaField to the form definition:

代码语言:javascript复制
from django import forms
from captcha.fields import CaptchaField

class CaptchaTestForm(forms.Form):
    myfield = AnyOtherField()
    captcha = CaptchaField()

…or, as a ModelForm:

代码语言:javascript复制
from django import forms
from captcha.fields import CaptchaField

class CaptchaTestModelForm(forms.ModelForm):
    captcha = CaptchaField()
    class Meta:
        model = MyModel

Validate the Form

In your view, validate the form as usual. If the user didn’t provide a valid response to the CAPTCHA challenge, the form will raise a ValidationError:

代码语言:javascript复制
def some_view(request):
    if request.POST:
        form = CaptchaTestForm(request.POST)

        # Validate the form: the captcha field will automatically
        # check the input
        if form.is_valid():
            human = True
    else:
        form = CaptchaTestForm()

    return render_to_response('template.html',locals())

Use to Template

代码语言:javascript复制
{{ form.captcha }}

Passing arguments to the field

CaptchaField takes a few optional arguements:

  • output_format will let you format the layout of the rendered field. Defaults to the value defined in : CAPTCHA_OUTPUT_FORMAT.
  • id_prefix Optional prefix that will be added to the ID attribute in the generated fields and labels, to be used when e.g. several Captcha fields are being displayed on a same page. (added in version 0.4.4)
  • generator Optional callable or module path to callable that will be used to generate the challenge and the response, e.g. generator='path.to.generator_function' or generator=lambda: ('LOL', 'LOL'), see also Generators and modifiers. Defaults to whatever is defined in settings.CAPTCHA_CHALLENGE_FUNCT.

Example usage for ajax form

An example CAPTCHA validation in AJAX:

代码语言:javascript复制
from django.views.generic.edit import CreateView
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url
from django.http import HttpResponse
import json

class AjaxExampleForm(CreateView):
    template_name = ''
    form_class = AjaxForm

    def form_invalid(self, form):
        if self.request.is_ajax():
            to_json_response = dict()
            to_json_response['status'] = 0
            to_json_response['form_errors'] = form.errors

            to_json_response['new_cptch_key'] = CaptchaStore.generate_key()
            to_json_response['new_cptch_image'] = captcha_image_url(to_json_response['new_cptch_key'])

            return HttpResponse(json.dumps(to_json_response), content_type='application/json')

    def form_valid(self, form):
        form.save()
        if self.request.is_ajax():
            to_json_response = dict()
            to_json_response['status'] = 1

            to_json_response['new_cptch_key'] = CaptchaStore.generate_key()
            to_json_response['new_cptch_image'] = captcha_image_url(to_json_response['new_cptch_key'])

            return HttpResponse(json.dumps(to_json_response), content_type='application/json')

And in javascript your must update the image and hidden input in form

Example usage ajax refresh button

# html:

代码语言:javascript复制
<form action='.' method='POST'>
    {{ form }}
    <input type="submit" />
    <button class='js-captcha-refresh'></button>
</form>

# javascript:

代码语言:javascript复制
$('.js-captcha-refresh').click(function(){
    $form = $(this).parents('form');

    $.getJSON($(this).data('url'), {}, function(json) {
        // This should update your captcha image src and captcha hidden input
    });

    return false;
});

Example usage ajax refresh

# javascript:

代码语言:javascript复制
$('.captcha').click(function () {
    $.getJSON("/captcha/refresh/", function (result) {
        $('.captcha').attr('src', result['image_url']);
        $('#id_captcha_0').val(result['key'])
    });


});

个人用法

个人使用时未使用到 Django 的表单的验证,直接在前端用 ajax 获取验证码,加了 1 分钟缓存,即 1 分钟只能获取一次,除非使用掉。

view 里调用生成验证码的代码

代码语言:javascript复制
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url

from ipware.ip import get_ip

def view_test(request):
	# hashkey 验证码生成的秘钥,image_url 验证码的图片地址
	hashkey_name = "hashkey_%s" % get_ip(request)
	hashkey = cache.get(hashkey_name)
	if not hashkey:
	    hashkey= CaptchaStore.generate_key()
	    cache.set(hashkey_name, hashkey, 60 * 1)
	image_url = captcha_image_url(hashkey)

	return ""  # 此处省略

改造后的 captcha/views.py 的 captcha_refresh 函数,加入了 1 分钟缓存

代码语言:javascript复制
def captcha_refresh(request):
    """  Return json with new captcha for ajax refresh request """
    ip = get_ip(request)
    if not request.is_ajax():
        raise Http404

    if cache.get("hashkey_%s" % ip):
        to_json_response = {
            'code': 403,
            'msg': "1 分钟内只能获取 1 次验证码"
        }
        return HttpResponse(json.dumps(to_json_response), content_type='application/json')

    new_key = CaptchaStore.pick(ip=ip)
    cache.set("hashkey_%s" % ip, new_key, 60 * 1)  # 1 分钟获取 1 次
    to_json_response = {
        'code': 200,
        'key': new_key,
        'image_url': captcha_image_url(new_key),
        'audio_url': captcha_audio_url(new_key) if settings.CAPTCHA_FLITE_PATH else None
    }
    return HttpResponse(json.dumps(to_json_response), content_type='application/json')

前端代码,获取验证码图片

代码语言:javascript复制
<div class="m-form-group am-u-sm-6 blog-clear-right">
    <div class="am-input-group">
        <input autocomplete="off" id="id_captcha_1" name="captcha_code" type="text"
               placeholder="* 验证码" class="am-form-field" required="required">
        <span class="am-input-group-btn">
            <img src="{{ image_url }}" alt="captcha" class="captcha" id="captcha"
                 style="height: 38px;">
        </span>

        <input id="id_reg_captcha_0" name="captcha_hashkey" type="hidden" value="{{ hashkey }}">
    </div>
    <script>
        $('#captcha').click(function () {
            $.getJSON("/captcha/refresh/", function (result) {
                if (result['code'] === 200) {
                    $('#captcha').attr('src', result['image_url']);
                    $('#id_reg_captcha_0').val(result['key'])
                } else {
                    toastr.warning(result['msg']);
                }
            });

        });
    </script>
</div>

view 里验证验证码是否有效,有效则在数据库表里 删除该条数据 以及 删除 1 分钟的缓存 key

代码语言:javascript复制
from captcha.models import CaptchaStore
from captcha.helpers import captcha_image_url

from ipware.ip import get_ip


def view_test_2(request):
	ip = get_ip(request)

	# 前端回传:captcha_code 验证码的值,captcha_hashkey 哈希之后的值
    captcha_code = request.POST.get("captcha_code".strip(), None)
    captcha_hashkey = request.POST.get("captcha_hashkey", None)
    try:
        # 如果没过期找到了就删除掉
        CaptchaStore.objects.get(response=captcha_code.lower(), hashkey=captcha_hashkey,
                                 expiration__gt=timezone.now()).delete()
        if cache.has_key("hashkey_%s" % ip):
            # 验证通过,如果还存在 key, 就删除掉
            cache.delete("hashkey_%s" % ip)

    except CaptchaStore.DoesNotExist:
        return HttpResponse("验证码无效或已过期")

	return ""  # 此处省略

其他用法

https://my.oschina.net/hellotest/blog/1623597

0 人点赞