8. 图片验证码

阅读: 70033     评论:51

为了防止机器人频繁登录网站或者破坏分子恶意登录,很多用户登录和注册系统都提供了图形验证码功能。

验证码(CAPTCHA)是“Completely Automated Public Turing test to tell Computers and Humans Apart”(全自动区分计算机和人类的图灵测试)的缩写,是一种区分用户是计算机还是人的公共全自动程序。可以防止恶意破解密码、刷票、论坛灌水,有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。

图形验证码的历史比较悠久,到现在已经有点英雄末路的味道了。因为机器学习、图像识别的存在,机器人已经可以比较正确的识别图像内的字符了。但不管怎么说,作为一种防御手段,至少还是可以抵挡一些低级入门的攻击手段,抬高了攻击者的门槛。

在Django中实现图片验证码功能非常简单,有现成的第三方库可以使用,我们不必自己开发(也要能开发得出来,囧)。这个库叫做django-simple-captcha

一、安装captcha

在Pycharm的terminal中,使用pip安装第三方库:

执行命令:pip install django-simple-captcha
(venv) D:\work\2019\for_test\mysite>pip install django-simple-captcha
Collecting django-simple-captcha
  Downloading https://files.pythonhosted.org/packages/86/d4/5baf10bfc9eb7844872c256898a405e81f22f7213e008ec90875689f913d/django-simple-captcha-0
.5.11.zip (234kB)
    100% |████████████████████████████████| 235kB 596kB/s
Collecting six>=1.2.0 (from django-simple-captcha)
  Downloading https://files.pythonhosted.org/packages/73/fb/00a976f728d0d1fecfe898238ce23f502a721c0ac0ecfedb80e0d88c64e9/six-1.12.0-py2.py3-none
-any.whl
Requirement already satisfied: Django>=1.8 in d:\work\2019\for_test\mysite\venv\lib\site-packages (from django-simple-captcha) (2.2)
Collecting Pillow!=5.1.0,>=2.2.2 (from django-simple-captcha)
  Downloading https://files.pythonhosted.org/packages/40/f2/a424d4d5dd6aa8c26636969decbb3da1c01286d344e71429b1d648bccb64/Pillow-6.0.0-cp37-cp37m
-win_amd64.whl (2.0MB)
    100% |████████████████████████████████| 2.0MB 2.2MB/s
Collecting django-ranged-response==0.2.0 (from django-simple-captcha)
  Downloading https://files.pythonhosted.org/packages/70/e3/9372fcdca8e9c3205e7979528ccd1a14354a9a24d38efff11c1846ff8bf1/django-ranged-response-
0.2.0.tar.gz
Requirement already satisfied: sqlparse in d:\work\2019\for_test\mysite\venv\lib\site-packages (from Django>=1.8->django-simple-captcha) (0.3.0)

Requirement already satisfied: pytz in d:\work\2019\for_test\mysite\venv\lib\site-packages (from Django>=1.8->django-simple-captcha) (2018.9)
Installing collected packages: six, Pillow, django-ranged-response, django-simple-captcha
  Running setup.py install for django-ranged-response ... done
  Running setup.py install for django-simple-captcha ... done
Successfully installed Pillow-6.0.0 django-ranged-response-0.2.0 django-simple-captcha-0.5.11 six-1.12.0

pip自动帮我们安装了相关的依赖库sixolefilePillow,其中的Pillow是大名鼎鼎的绘图模块。

二、注册captcha

在settings中,将‘captcha’注册到app列表里:

# Application definition

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'login',
    'captcha',
]

captcha需要在数据库中建立自己的数据表,所以需要执行migrate命令生成数据表:

(venv) D:\work\2019\for_test\mysite>python manage.py migrate
Operations to perform:
  Apply all migrations: admin, auth, captcha, contenttypes, login, sessions
Running migrations:
  Applying captcha.0001_initial... OK

三、添加url路由

在根目录下的urls.py文件中增加captcha对应的url:

from django.contrib import admin
from django.urls import path
from django.urls import include
from login import views

urlpatterns = [
    path('admin/', admin.site.urls),
    path('index/', views.index),
    path('login/', views.login),
    path('register/', views.register),
    path('logout/', views.logout),
    path('captcha/', include('captcha.urls'))   # 增加这一行
]

由于使用了二级路由机制,需要在顶部from django.urls import include

四、修改forms.py

如果上面都OK了,就可以直接在我们的forms.py文件中添加CaptchaField了。

from django import forms
from captcha.fields import CaptchaField

class UserForm(forms.Form):
    username = forms.CharField(label="用户名", max_length=128, widget=forms.TextInput(attrs={'class': 'form-control', 'placeholder': "Username",'autofocus': ''}))
    password = forms.CharField(label="密码", max_length=256, widget=forms.PasswordInput(attrs={'class': 'form-control',  'placeholder': "Password"}))
    captcha = CaptchaField(label='验证码')

注意需要提前导入from captcha.fields import CaptchaField,然后就像写普通的form字段一样添加一个captcha字段就可以了!

五、修改login.html

由于我们前面是手动生成的form表单,所以还要修改一下,添加captcha的相关内容,如下所示:

{% load static %}
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
    <!-- 上述meta标签*必须*放在最前面,任何其他内容都*必须*跟随其后! -->
    <!-- Bootstrap CSS -->
    <link href="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
    <link href="{% static 'login/css/login.css' %}" rel="stylesheet"/>
    <title>登录</title>
  </head>
  <body>
    <div class="container">
            <div class="col">
                <form class="form-login" action="/login/" method="post">

                {% if login_form.captcha.errors %}
                    <div class="alert alert-warning">{{ login_form.captcha.errors }}</div>
                {% elif message %}
                    <div class="alert alert-warning">{{ message }}</div>
                {% endif %}

                  {% csrf_token %}
                  <h3 class="text-center">欢迎登录</h3>

                  <div class="form-group">
                    {{ login_form.username.label_tag }}
                    {{ login_form.username}}
                  </div>

                  <div class="form-group">
                    {{ login_form.password.label_tag }}
                    {{ login_form.password }}
                  </div>

                  <div class="form-group">
                    {{ login_form.captcha.label_tag }}
                    {{ login_form.captcha }}
                  </div>

                  <div>
                      <a href="/register/" class="text-success " ><ins>新用户注册</ins></a>
                      <button type="submit" class="btn btn-primary float-right">登录</button>
                  </div>
                </form>
            </div>
    </div> <!-- /container -->

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    {#    以下三者的引用顺序是固定的#}
    <script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
    <script src="https://cdn.bootcss.com/popper.js/1.15.0/umd/popper.js"></script>
    <script src="https://cdn.bootcss.com/twitter-bootstrap/4.3.1/js/bootstrap.min.js"></script>

  </body>
</html>

这里在顶部的消息处,在{% if %}模板代码中,额外增加了一条{{ login_form.captcha.errors }}的判断,用于明确指示用户的验证码不正确。

六、查看效果

重启服务器,进入登录页面,尝试用用户名错误、密码不对、验证码不对、全对的不同情况,看看我们新增的四位验证码的效果如何。

image

image

就是这么简单!我们加入了一个防止机器人或者恶意登录的图形验证码功能,虽然界面难看了点,但底子是好的,你可以根据需要进行美化。其中验证图形码是否正确的工作都是在后台自动完成的,只需要使用is_valid()这个forms内置的验证方法就一起进行了,完全不需要在视图函数中添加任何的验证代码,非常方便快捷!

关于captcha的功能,当然绝不仅限于此,你可以设置六位、八位验证码,可以对图形噪点的生成模式进行定制,这些就留待你自己学习和研究了。


 7. Django表单 9. session会话 

评论总数: 51


点击登录后方可评论

这个可以直接使用,实现点击更换验证码,放入html就可以了。 <script>//验证码动态刷新实现 $('.captcha').click(function () { $.getJSON("/captcha/refresh/", function (result) { $('.captcha').attr('src', result['image_url']); $('#id_captcha_0').val(result['key']) }); }); </script>



请问在postman如何调试输入图片验证码呢



老师 我在安装的时候报这两个错 ERROR: Could not find a version that satisfies the requirement django-simple-captcha (from versions: none) ERROR: No matching distribution found for django-simple-captcha 我在网上找不到解决办法



已经解决了



老师,为啥我还是会报错ModuleNotFoundError: No module named 'captcha',在pycharm的setting可以看到我装的captcha,而且setting.py的内容和老师的也是一样的。还有这个错:OSError: [WinError 123] 文件名、目录名或卷标语法不正确。: '<frozen importlib._bootstrap>'。而且奇怪的是我可以python manage.py runserver强制运行,但是一些验证输入和验证码都是没有的。我直接点绿色三角形运行就会报那两个错。有没有什么解决办法?



查看一下你的captcha安装到哪里了



找到最简单的方法刷新就一段js <script> $('img.captcha').click(function() { $.getJSON('/captcha/refresh/',function(json) { // This should update your captcha image src and captcha hidden input console.log(json); $("img.captcha").attr("src",json.image_url); $("#id_captcha_0").val(json.key); }); return false; }); </script>



想知道如何设计点击验证码刷新的功能 照着网上找的做了几个都失败了...



通过ajax发送刷新请求,获取新图片后,刷新页面。



请问老师可以具体把步骤写出来么 麻烦您了



博主请问一下,为什么验证码的图片加载不了??



C:\Users\陈\AppData\Local\Programs\Python\Python36\Lib\site-packages\captcha\fonts 此路径下的Vera.tff字体需要安装 默认字体一般没安装 可以安装 也可以修改字体



请问,captcha都设置好了之后,makemigrations提示: no module named 'logincaptcha' 怎么解决呢,服务器始终运行不起来了



如果我没猜错的话,你在注册app的时候,login字符串后面没有加逗号.....



hahaha,和我遇到的问题一样。就是login后面没有逗号。



刘老师,您好,我的验证码图片资源请求不到,加载不出来,500. UnicodeDecodeError: 'gbk' codec can't decode byte 0xa6 in position 9737: illegal multibyte sequence



按照教程一步一步来,验证码输入错误,没有图示中“认证码错误”。账号密码正确,验证码错误提示“请检查填写的内容”。 我哪里不对吗?



{% if login_from.captcha.errors %} <div class="alert alert-warning">{{ login_from.captcha.errors }}</div> 这一步未生效



那请问你是怎么解决的 我也有相同的问题



views.py文件中,login()函数login_form.is_valid()校验失败,导致一直返回在函数开头定义的message变量值。在if对应位置添加else,返回包含请求的login_form。 if login_form.is_valid(): ...... else: return render(request, "login/login.html", locals())



您好,请问这个验证码图片为什么会无法显示呀?



你好 老师 那个我注册成功返回登录界面的时候 为什么登录框那些都渲染不出来啊 要刷新才可以



您好,之前用的是anaconda ,所以就用这个创建了虚拟环境,anaconda没有django-simple-captcha这个包,用pip 命令没把这个包安装到虚拟环境



已解决



你好,如何解决的?



估计是Py版本的问题



<div class="form-group"> {{ login_form.captcha.errors }} {{ login_form.captcha.label_tag }} {{ login_form.captcha }} </div>





请问刘老师,任何实现单击刷新验证码?



点击图片,发送请求,后台更新验证码,返回前端



刘老师,验证码错误不显示,好像是显示一瞬间就没了,这是怎么回事呢?



刘老师,我想美化验证码,可是尝试用户名那样美化,但是发现不行,因为要显示图片,老师能否给个思路啊



查了好多资料,都没找到一个办法美化验证码,毕竟里面要显示一个图片,但是django提供的widget里面没有这种,我还查了captcha,也只是没有提供的,还是用html来写验证码再美化方便点吧,django的这个方便,但是限制太多



1.自己实现,2.找现成的库 ,3.修改captcha等等。



您可以试试通过配置及覆盖模板的方式: 一.在setting.py文件中添加 # capthca设置 CAPTCHA_IMAGE_SIZE=(88,45) CAPTCHA_TIMEOUT=1 CAPTCHA_FIELD_TEMPLATE =BASE_DIR+"/templates/captcha/text_field.html" CAPTCHA_OUTPUT_FORMAT=u'%(text_field)s %(hidden_field)s %(image)s' 二.模板文件:login/templates/captcha/text_field.html <input autocapitalize="off" autocomplete="off" autocorrect="off" spellcheck="false" id="{{id}}_1" name="{{name}}_1" class='form-control' type="text" style="width:150px;display:inline" placeholder="请输入验证码" />



https://django-simple-captcha.readthedocs.io/en/latest/usage.html官方文档有说明,导入from captcha.fields import CaptchaField,CaptchaTextInput,就可以进行自定义渲染



研究了好一会没搞懂。。直接上css了。。在验证码输入框,采用了一个十分粗暴的方法, 修改了captcha的模板,captcha/templates/captcha/text_field.html



验证码的图是裂的...



captcha这个app是自动创建的吗?没有看到哪里有写.



已经解决 谢谢



我并没有理解captch在哪里 现在提示No module named 'captcha.fields'



同问



为什么我的验证码错误提示不出现???



请问解决了吗?



出来了,有个地方写错了。



哪里写错了会影响啊



我也一样,最后手动验证把异常传回去了,勉强完成



这里INSTALLED_APPS中加入的captcha,是自己再次创建的APP吧?



找到了



在哪里找到的啊?



明白了 已经解决 谢谢