Django开发技术第八式---登录验证码

1、建立Django项目 TOTO

 2、生成系统数据库user

(1)迁移数据库

(2) 创建超级用户数据

得到:

3、登录页面、验证码(1.0)

login.html

<!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">

</head>
<body>
<h3>登录页面</h3>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label for="">用户:</label>
                    <input type="text" class="form-control" id="user">
                </div>
                <div class="form-group">
                    <label for="">密码:</label>
                    <input type="password" class="form-control" id="pwd">
                </div>
                <div class="form-group">
                    <label for="">验证码:</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="yzm">
                        </div>
                        <div class="col-md-6">
                            <img width="200" height="40" src="/get_valid_img/" alt="">
                        </div>
                    </div>


                </div>
                <input type="button" class="btn btn-primary pull-right" value="提交">
            </form>

        </div>
    </div>
</div>
</body>
</html>

views.py

#coding:utf-8
from django.shortcuts import render,HttpResponse
import PIL
from PIL import Image
import random

# Create your views here.

#此处可以放到任何py文件中
def login(request):
    if request.method=="GET":

        return render(request,"login.html")
    else:
        pass

#验证码
def get_valid_img(request):
    #方式1:读取指定图片
    # with open("static/img/yzm.jpg","rb") as f:
    #     data = f.read()

    #方式2:基于PIL库创建验证码图片
    #二维码背景图随机生成颜色
    def get_random_color():
        return (random.randint(0,255),random.randint(0,255),random.randint(0,255))#随机生成三个0-255之间的元组
    img = Image.new("RGB",(350,46),get_random_color())#创建一张新的图片
    f = open("yzm.png","wb")#将生成的图片保存在yzm.png中
    img.save(f,"png")#保存为png格式

    with open("yzm.png","rb") as f:
        data = f.read()

    return HttpResponse(data)#将数据发送出去

运行结果:

验证码2.0

views.py

    #方式3:
    img = Image.new("RGB",(350,38),get_random_color())
    f = BytesIO()
    img.save(f,"png")#将图片进行存储到内存,不会保存在磁盘中,每次结束后会进行清除内存
    data = f.getvalue()#在内存中读取图片数据

    return HttpResponse(data)#将数据发送出去

运行结果:

验证码3.0,(此处应当先下载ttf字体)

    img = Image.new("RGB", (350, 38), get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/fonts/yiyang.ttf",32)
    draw.text((10,0),"xiaokeai",get_random_color(),font=font)


    #写与读
    f = BytesIO()
    img.save(f,"png")#将图片进行存储到内存,不会保存在磁盘中,每次结束后会进行清除内存
    data = f.getvalue()#在内存中读取图片数据

运行结果:

验证码4.0

#方法5:
    img = Image.new("RGB", (350, 38), get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/fonts/yiyang.ttf", 32)

    keep_text = ""
    for i in range(6):
        #随机数字、字母
        random_num = str(random.randint(0,9))#生成0-9之间的随机数字
        random_low = chr(random.randint(97,122))#生成a-z之间的随机小写字母
        random_up = chr(random.randint(65,90))#生成A-Z之间的随机大写字母
        #再在数字、字母中随机选择一个
        random_text = random.choice([random_num,random_low,random_up])

        draw.text((i*40+70, 0), random_text, get_random_color(), font=font)
        keep_text += random_text#将验证码进行备份,进行校验

运行结果:

添加噪声、噪点

img = Image.new("RGB", (350, 38), get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/fonts/yiyang.ttf", 32)

    keep_text = ""
    for i in range(6):
        #随机数字、字母
        random_num = str(random.randint(0,9))#生成0-9之间的随机数字
        random_low = chr(random.randint(97,122))#生成a-z之间的随机小写字母
        random_up = chr(random.randint(65,90))#生成A-Z之间的随机大写字母
        #再在数字、字母中随机选择一个
        random_text = random.choice([random_num,random_low,random_up])

        draw.text((i*40+70, 0), random_text, get_random_color(), font=font)
        keep_text += random_text#将验证码进行备份,进行校验

    #添加噪声、噪点
    width =350
    height=38
    for i in range(10):
        x1=random.randint(0,width)
        x2=random.randint(0,width)
        y1=random.randint(0,height)
        y2=random.randint(0,height)
        draw.line((x1,y1,x2,y2),fill=get_random_color())

    for i in range(50):
        draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
        x = random.randint(0, width)
        y = random.randint(0, height)
        draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())

显示结果:

4、获取验证码信息并进行比对

views.py

#coding:utf-8
from django.shortcuts import render,HttpResponse
from django.http import JsonResponse
import PIL
from PIL import Image,ImageDraw,ImageFont
from django.contrib import auth
import random
from io import BytesIO

# Create your views here.

#此处可以放到任何py文件中
def login(request):

    # if request.method=="GET":
    #
    #     return render(request,"login.html")
    # else:
    #     pass

    #
    if request.is_ajax():
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        yzm = request.POST.get("yzm")

        #ajax请求返回一个字典
        response = {"user":None,"err_msg":""}
        if yzm.upper() == request.session.get("keep_text").upper():
            user_obj = auth.authenticate(username=user,password=pwd)
            if user_obj:
                response["user"] = user
            else:
                response["err_msg"] = "用户名或密码错误"


        # if yzm.upper() == request.session.get("keep_text").upper():
        #     return HttpResponse("OK")
        else:
            response["err_msg"] = "验证码错误"
        return JsonResponse(response)

    else:
        return render(request,"login.html")

#验证码
def get_valid_img(request):
    #方式1:读取指定图片
    # with open("static/img/yzm.jpg","rb") as f:
    #     data = f.read()

    # 二维码背景图随机生成颜色
    def get_random_color():
        return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))  # 随机生成三个0-255之间的元组

    #方式2:基于PIL库创建验证码图片

    # img = Image.new("RGB",(350,46),get_random_color())#创建一张新的图片
    # f = open("yzm.png","wb")#将生成的图片保存在yzm.png中
    # img.save(f,"png")#保存为png格式
    #
    # with open("yzm.png","rb") as f:
    #     data = f.read()

    #方式3:
    # img = Image.new("RGB",(350,38),get_random_color())
    # f = BytesIO()
    # img.save(f,"png")#将图片进行存储到内存,不会保存在磁盘中,每次结束后会进行清除内存
    # data = f.getvalue()#在内存中读取图片数据
    #


    #方式4:完善文本

    # img = Image.new("RGB", (350, 38), get_random_color())
    # draw = ImageDraw.Draw(img)
    # font = ImageFont.truetype("static/fonts/yiyang.ttf",32)
    # draw.text((10,0),"xiaokeai",get_random_color(),font=font)
    #
    #
    # #写与读
    # f = BytesIO()
    # img.save(f,"png")#将图片进行存储到内存,不会保存在磁盘中,每次结束后会进行清除内存
    # data = f.getvalue()#在内存中读取图片数据

    #方法5:
    img = Image.new("RGB", (350, 38), get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/fonts/yiyang.ttf", 32)

    global keep_text
    keep_text = ""

    for i in range(6):
        #随机数字、字母
        random_num = str(random.randint(0,9))#生成0-9之间的随机数字
        random_low = chr(random.randint(97,122))#生成a-z之间的随机小写字母
        random_up = chr(random.randint(65,90))#生成A-Z之间的随机大写字母
        #再在数字、字母中随机选择一个
        random_text = random.choice([random_num,random_low,random_up])

        draw.text((i*40+70, 0), random_text, get_random_color(), font=font)

        keep_text += random_text#将验证码进行备份,进行校验
    print("keep_text",keep_text)

    #将验证码存在各自的session中
    request.session["keep_text"] = keep_text


    #添加噪声、噪点
    # width =350
    # height=38
    # for i in range(10):
    #     x1=random.randint(0,width)
    #     x2=random.randint(0,width)
    #     y1=random.randint(0,height)
    #     y2=random.randint(0,height)
    #     draw.line((x1,y1,x2,y2),fill=get_random_color())
    #
    # for i in range(50):
    #     draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())


    # 写与读
    f = BytesIO()
    img.save(f, "png")  # 将图片进行存储到内存,不会保存在磁盘中,每次结束后会进行清除内存
    data = f.getvalue()  # 在内存中读取图片数据
    return HttpResponse(data)#将数据发送出去

验证码刷新

login.html

<!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">

</head>
<body>
<h3>登录页面</h3>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                {% csrf_token %}
                <div class="form-group">
                    <label for="">用户:</label>
                    <input type="text" class="form-control" id="user">
                </div>
                <div class="form-group">
                    <label for="">密码:</label>
                    <input type="password" class="form-control" id="pwd">
                </div>
                <div class="form-group">
                    <label for="">验证码:</label>
                    <div class="row">
                        <div class="col-md-6">
                            <input type="text" class="form-control" id="yzm">
                        </div>
                        <div class="col-md-6">
                            <img width="200" height="40" src="/get_valid_img/" alt="" id="img">
                        </div>
                    </div>


                </div>
                <input type="button" class="btn btn-primary pull-right login_btn" value="登录">
                <span class="error"></span>
            </form>

        </div>
    </div>
</div>

<script src="/static/js/jquery.js"></script>
<script>
    $(".login_btn").click(function () {
        $.ajax({
            url:"",
            type:"post",
            data:{
                user:$("#user").val(),
                pwd:$("#pwd").val(),
                yzm:$("#yzm").val(),
                csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()

            },
            success:function (response) {
                console.log(response);
                if(response.user){
                    //登录成功
                    location.href = "http://www.baidu.com"
                }
                else{
                    //登录失败
                    $(".error").html(response.err_msg).css("color","red")
                }
            }
        })
    })

    //验证码刷新
    $("#img").click(function(){
        this.src+="?"
    })
</script>
</body>
</html>

 运行结果:

 当验证码错误时:

验证码正确时,跳转到百度页面

5、用户认证组件用户的拓展

创建超级用户

6、显示注册的错误信息

(1)用户名不能短于5个字符

(2)密码不能短于5个字符,切不能为纯数字

(3)邮箱必须问163邮箱

views.py

from django.shortcuts import render,HttpResponse

# Create your views here.
import random

from django.http import JsonResponse

from django.contrib import auth
from django import forms

from django.core.exceptions import ValidationError
import re
from app01.models import UserInfo
from django.forms import widgets

class UserForm(forms.Form):
    user=forms.CharField(min_length=5,label="用户名")
    pwd=forms.CharField(min_length=5,widget=widgets.PasswordInput(),label="密码")
    r_pwd=forms.CharField(min_length=5,widget=widgets.PasswordInput(),label="确认密码")
    email=forms.EmailField(min_length=5,label="邮箱")

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        for filed in self.fields.values():
            filed.widget.attrs.update({'class': 'form-control'})


    def clean_user(self):
        val=self.cleaned_data.get("user")
        user=UserInfo.objects.filter(username=val).first()
        if user:
            raise ValidationError("用户已存在!")
        else:
            return val

    def clean_pwd(self):
        val=self.cleaned_data.get("pwd")
        if val.isdigit():
            raise ValidationError("密码不能是纯数字!")
        else:
            return val

    def clean_email(self):
        val=self.cleaned_data.get("email")
        if re.search("\[email protected]$",val):
            return val
        else:
            raise ValidationError("邮箱必须是163邮箱!")

    def clean(self):
        pwd=self.cleaned_data.get("pwd")
        r_pwd=self.cleaned_data.get("r_pwd")

        if pwd and r_pwd and r_pwd!=pwd:
            self.add_error("r_pwd", ValidationError("两次密码不一致!"))
        else:
            return self.cleaned_data











def login(request):

    # if request.method=="POST":
    if request.is_ajax():
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")
        yzm=request.POST.get("yzm")

        #Ajax请求返回一个字典
        response={"user":None,"err_msg":""}
        if yzm.upper() == request.session.get("keep_str").upper():
            user_obj=auth.authenticate(username=user,password=pwd)
            if user_obj:
                response["user"]=user
            else:
                response['err_msg']="用户名或者密码错误!"
        else:
            response["err_msg"]="验证码错误!"

        return JsonResponse(response)


    else:
        return render(request, "login.html")


def get_valid_img(request):

    #  方式1:读取指定图片
    # with open("static/img/valid.jpg","rb") as f:
    #     data=f.read()


    # 方式2:基于PIL模块创建验证码图片
    from PIL import Image,ImageDraw,ImageFont
    from io import BytesIO


    def get_random_color():
        import random
        return (random.randint(0,255),random.randint(0,255),random.randint(0,255))
    #
    # img=Image.new("RGB",(350,38),get_random_color())
    # f=open("valid.png","wb")
    # img.save(f,"png")
    # with open("valid.png","rb") as f:
    #     data=f.read()

    # 方式3:
    # img=Image.new("RGB",(350,38),get_random_color())
    # f=BytesIO()
    # img.save(f,"png")
    # data=f.getvalue()

    # # 方式4:完善文本
    #
    # img=Image.new("RGB",(350,38),get_random_color())
    # draw=ImageDraw.Draw(img)
    # font=ImageFont.truetype("static/font/kumo.ttf",32)
    # draw.text((0,0),"python!",get_random_color(),font=font)
    #
    # # 写与读
    # f=BytesIO()
    # img.save(f,"png")
    # data=f.getvalue()

    # 方式5:

    img = Image.new("RGB", (350, 38), get_random_color())
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype("static/fonts/yiyang.ttf", 32)

    keep_str=""
    for i in range(6):
        random_num = str(random.randint(0, 9))
        random_lowalf = chr(random.randint(97, 122))
        random_upperalf = chr(random.randint(65, 90))
        random_char=random.choice([random_num,random_lowalf,random_upperalf])
        draw.text((i*30+50,0),random_char, get_random_color(), font=font)
        keep_str+=random_char


    # width=350
    # height=38
    # for i in range(100):
    #     x1=random.randint(0,width)
    #     x2=random.randint(0,width)
    #     y1=random.randint(0,height)
    #     y2=random.randint(0,height)
    #     draw.line((x1,y1,x2,y2),fill=get_random_color())
    #
    # for i in range(500):
    #     draw.point([random.randint(0, width), random.randint(0, height)], fill=get_random_color())
    #     x = random.randint(0, width)
    #     y = random.randint(0, height)
    #     draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_random_color())
    # 写与读
    f = BytesIO()
    img.save(f, "png")
    data = f.getvalue()

    print('keep_str',keep_str)

    # 将验证码存在各自的session中

    request.session['keep_str']=keep_str

    return HttpResponse(data)


def reg(request):

    if request.method=="POST":
        print(request.POST)
        form=UserForm(request.POST)
        res={"user":None,"err_msg":""}
        if form.is_valid():
            res["user"]=form.cleaned_data.get("user")
            print("cleaned_data",form.cleaned_data)
            user=form.cleaned_data.get("user")
            pwd=form.cleaned_data.get("pwd")
            email=form.cleaned_data.get("email")

            user=UserInfo.objects.create_user(username=user,password=pwd,email=email)


        else:
            print(form.errors)
            print(form.cleaned_data)
            res["err_msg"] =form.errors

        return JsonResponse(res)


    else:
        form=UserForm()
        return  render(request,"reg.html",locals())

注册页面:

reg.html

<!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">

</head>
<body>
<h3>注册页面</h3>

<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post">
                {% csrf_token %}
                {% for field in form %}
                    <div class="form-group">
                        <label for="">{{ field.label }}</label>
                        {{ field }}
                        <span class="error pull-right"></span>
                    </div>


                {% endfor %}


                <input type="button" class="btn btn-primary reg_btn" value="注册">

            </form>

        </div>
    </div>
</div>

<script src="/static/js/jquery.js"></script>
<script>
    $(".reg_btn").click(function () {
       $.ajax({
           url:"",
           type:"post",
           data:{
               user:$("#id_user").val(),
               pwd:$("#id_pwd").val(),
               r_pwd:$("#id_r_pwd").val(),
               email:$("#id_email").val(),
               csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()

           },
           success:function (res) {
               console.log(res);

               if(res.user){
                   //注册成功
                   location.href="/login/"
               }
               else {
                   //清除错误
                   $(".error").html("");
                   $(".form-group").removeClass("has-error");

                   //显示新的错误
                   $.each(res.err_msg,function (i,j) {
                       console.log(i,j);
                       $("#id_"+i).next().html(j[0]).css("color","red").parent().addClass("has-error");
                   })
               }


           }
       })
    })
</script>
</body>
</html>

整个运行如下:

注册页面:

登录页面:

登陆之后跳转到指定页面:

本期学习结束,欢迎关注交流。

发布了78 篇原创文章 · 获赞 5 · 访问量 8308

猜你喜欢

转载自blog.csdn.net/qq_36789311/article/details/100639776
今日推荐