基于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>

原文地址:https://www.cnblogs.com/pythonyeyu/p/11648123.html

时间: 2024-11-29 06:13:33

基于django实现图文验证码两种方式的相关文章

从源代码剖析Struts2中用户自定义配置转换器的两种方式——基于字段的配置转换器和基于类型的配置转换器(解决了实际系统中,因没有区分这两种工作方式的生命周期而引起的异常错误问题)

自定义类型转换器必须实现ongl.TypeConverter接口或对这个接口的某种具体实现做扩展 <<interface>>com.opensymphony.xwork2.conversion.TypeConverter à com.opensymphony.xwork2.conversion.impl.DefaultTypeConverter à org.apache.struts2.util.StrutsTypeConverter 接口及类进行解析 TypeConverter(

在基于MVC的Web项目中使用Web API和直接连接两种方式混合式接入

在我之前介绍的混合式开发框架中,其界面是基于Winform的实现方式,后台使用Web API.WCF服务以及直接连接数据库的几种方式混合式接入,在Web项目中我们也可以采用这种方式实现混合式的接入方式,虽然Web API或者WCF方式的调用,相对直接连接数据库方式,响应效率上略差一些,不过扩展性强,也可以调动更多的设备接入,包括移动应用接入,网站接入,Winfrom客户端接入,这样可以使得服务逻辑相对独立,负责提供接口即可.这种方式中最有代表性的就是当前Web API的广泛应用,促进了各个接入端

Python 实现接口类的两种方式+邮件提醒+动态导入模块+反射(参考Django中间件源码)

实现接口类的两种方式 方式一 from abc import ABCMeta from abc import abstractmethod class BaseMessage(metaclass=ABCMeta): @abstractmethod def send(self,subject,body,to,name): pass 方式二 class BaseMessage(object): def send(self, subject, body, to, name): raise NotImp

五 Mybatis一对一关联查询的两种方式(基于resultType&amp;基于resultMap)

关联查询: 一个用户对应多个订单,一个订单只有一个用户 订单关联用户:两种方式 一:基于resultTYpe是一个与表关系一样的pojo实现 主表订单,从表用户 首先要有一个与关联查询表关系一样的pojo 在代理接口添加方法,配置代理映射 最后进行单元测试  二 : 基于resultMap(推荐) pojo:在订单类中放置用户类对象,并且提供对应的setget方法  在ResultMap中配置两表关系 基于resultMap配置关联查询的方法 单元测试: 原文地址:https://www.cnb

SpringBoot集成Mybatis实现多表查询的两种方式(基于xml)

 下面将在用户和账户进行一对一查询的基础上进行介绍SpringBoot集成Mybatis实现多表查询的基于xml的两种方式.   首先我们先创建两个数据库表,分别是user用户表和account账户表     user表:  account表:  然后创建实体类        **第一种通过创建子类的方式查询                             需求:查询所有的用户基础信息以及其所属的账户中的金额     1.创建想要得到多表查询数据的实体类(子类)            

基于Maven的SpringBoot项目实现热部署的两种方式

下面我将介绍使用maven构建的SpringBoot项目中实现热部署的两种方式,使得部署变得异常简单,同时两种方式也非常的简单. 热部署 devtools Pom.xml中直接添加依赖即可: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-devtools</artifactId> <scope>provided</

生成二维码的两种方式

利用qrcode生成二维码,(qrcode矩形二维码符号) 基于jquery的二维码生成插件qrcode,在页面中调用该插件就能生成对应的二维码.qrcode其实是通过使用jQuery实现图形渲染,画图,支持canvas(HTML5)和table两种方式: 使用插件时 1.首先在页面中加入jquery库文件和qrcode插件. <script type="text/javascript" src="jquery.js"></script> &

《连载 | 物联网框架ServerSuperIO教程》- 10持续传输大块数据流的两种方式(如:文件)

1.C#跨平台物联网通讯框架ServerSuperIO(SSIO)介绍 <连载 | 物联网框架ServerSuperIO教程>1.4种通讯模式机制. <连载 | 物联网框架ServerSuperIO教程>2.服务实例的配置参数说明 <连载 | 物联网框架ServerSuperIO教程>- 3.设备驱动介绍 <连载 | 物联网框架ServerSuperIO教程>-4.如开发一套设备驱动,同时支持串口和网络通讯. <连载 | 物联网框架ServerSupe

WebService的两种方式SOAP和REST比较 (转)

我的读后感:由于第一次接触WebService,对于很多概念不太理解,尤其是看到各个OpenAPI的不同提供方式时,更加疑惑.如google map api采用了AJAX方式,通过javascript提供API,而淘宝TOP则采用直接的HTTP+XML请求方式,最令我疑惑的是教材上讲的WSDL,UDDI从没有在这些API中出现过.现在知道了WebService原来有两种方式,一是SOAP协议方式,在这种方式下需要WSDL,UDDI等,二是REST方式,这种方式根本不需要WSDL,UDDI等.而且