zl程序教程

您现在的位置是:首页 >  后端

当前栏目

20.Django大型电商项目之登录页面、如何使用图片验证码

django项目 如何 图片 页面 登录 20 电商
2023-09-27 14:23:04 时间

1. 登录页面

1.1 基础搭建

templates

<!-- netshop\userapp\templates\userapp\login.html -->
{% extends 'base.html' %}
{% block title %}用户登录页面{% endblock %}

{% load static %}
{% block headerjs %}
<script type="text/javascript" src="{% static 'js/md5-min.js' %}"></script>
{% endblock %}

{% block main %}
<div class="login-body">
    <div class="login-card">
        <div class="login-top">
            <h3>新用户登录</h3>
            <h5>尊敬的用户,欢迎您回来!</h5>
        </div>
        <div class="login-bottom">
            <form method="post" action="http://127.0.0.1:8000/user/login/" onsubmit="login();">
                <input type="hidden" name="time" id="time">
                <div class="login-input-box">
                    <input type="hidden" name="csrfmiddlewaretoken"
                        value="Bk9p9oIn87TIw7edTgOWAyjWHDRZOOts0scYwmO9rCQau6nNudBBS3NFtbK5gLk1">

                    <input type="text" id="account" name="account" value="" class="login-admin active"
                        placeholder="邮箱登录">
                    <span style="color:red;" id="aSpan"></span>

                    <input type="password" id="password" name="password" value="" class="login-password">
                    <span style="color:red;" id="pSpan"></span>

                    <input type="text" style="height:36px;width: 100px;" id="code" onblur="checkCode(this.value)"><img
                        src="./首页_files/saved_resource" onclick="changeCode(this)"><span style="color:red;"
                        id="cSpan"></span>

                    <input type="hidden" name="redirect" value="">
                    <input type="hidden" name="cartitems" value="None">

                    <button class="login-btn" style="color: white;text-decoration: none;cursor: pointer">登录</button>
                </div>
            </form>
            <div class="login-img">
                <img src="{% static 'images/login_05.png' %}" alt="">
            </div>
        </div>
    </div>
</div>

{% endblock %}

{% block footerjs %}
<script>
    function isEmail(str) {
        var reg = /^[a-zA-Z0-9_-]{6,}@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
        return reg.test(str);
    }

    function login() {
        //获取输入框的值
        var account = $('#account').val();
        var password = $('#password').val();

        //简单校验
        if (account.length < 6 || !isEmail(account)) {
            $('#aSpan').text('邮箱长度不能小于六位');
            return false;
        }

        if (password.length < 6) {
            $('#pSpan').text('密码长度不能小于六位');
            return false;
        }

        var code = $('#code').val();
        var cflag = checkCode(code);

        if (!cflag) {
            $('cSpan').text('×');
            return false;
        }

        var time = new Date().getTime();
        $('#time').val(time)


        var hex_pwd = hex_md5(password);

        //var hex_pwd = hex_md5(password+time)
        $('#password').val(hex_pwd);

    }


    //切换验证码
    function changeCode(obj) {
        $(obj).attr('src', '/user/vcode/?r=' + new Date().getTime())
    }


    function checkCode(txt) {
        var cflag = false;
        $.ajax({
            url: '/user/checkcode/',
            type: 'get',
            data: { 'code': txt },
            async: false,
            success: function (result) {
                var flag = result.checkFlag;
                if (flag) {
                    cflag = true;
                    $('cSpan').text('√');
                } else {
                    $('cSpan').text('×');
                }
            }
        })

        return cflag;

    }

</script>
{% endblock %}

views

# netshop\userapp\views.py
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from userapp.models import *
import jsonpickle
# 用户登录
class LoginView(View):
    def get(self,request):
        return render(request, 'userapp/login.html')
    def post(self, request):
        pass

urls

# netshop\userapp\urls.py
from django.contrib import admin
from django.urls import path,include
from userapp import views
urlpatterns = [
    path('register/',views.Register.as_view()),
    path('center/',views.userCenter),
    path('login/',views.LoginView.as_view())
]

在这里插入图片描述

1.2 captcha生成验证码

生成验证码函数

#encoding=utf-8
import random
from PIL import Image,ImageDraw,ImageFont,ImageFilter

#生成几位数的验证码
from io import BytesIO

number = 4
#生成验证码图片的高度和宽度
size = (129,53)
#背景颜色,默认为白色
bgcolor = (255,255,255)
#字体颜色,默认为蓝色
fontcolor = (0,0,0)
#干扰线颜色。默认为红色
linecolor = (0,0,0)
#是否要加入干扰线
draw_line = True
#加入干扰线条数的上下限
line_number = (1,5)

#用来随机生成一个字符串
def gene_text():
    # source = list(string.letters)
    # for index in range(0,10):
    #     source.append(str(index))
    source = ['0','1','2','3','4','5','6','7','8','9']
    # source = [ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H','I','J', 'K','L', 'M', 'N','O','P','Q','R',
            #   'S', 'T', 'U', 'V', 'W', 'Z','X', 'Y']
    return ''.join(random.sample(source,number))#number是生成验证码的位数
#用来绘制干扰线
def gene_line(draw,width,height):
    # begin = (random.randint(0, width), random.randint(0, height))
    # end = (random.randint(0, width), random.randint(0, height))
    begin = (0, random.randint(0, height)) # 起点
    end = (74, random.randint(0, height)) # 终点
    draw.line([begin, end], fill = linecolor,width=3)

#生成验证码
def gene_code():
    width,height = size #宽和高
    image = Image.new('RGBA',(width,height),bgcolor) #创建图片
    import  os
    path = os.path.join(os.getcwd(),'utils','Arial.ttf')
    font = ImageFont.truetype(path,36) #验证码的字体
    draw = ImageDraw.Draw(image)  #创建画笔
    text = gene_text() #生成字符串
    font_width, font_height = font.getsize(text)
    draw.text(((width - font_width) / number, (height - font_height) / number),text,\
            font= font,fill=fontcolor) #填充字符串
    if draw_line:
        gene_line(draw,width,height)
    image = image.transform((width+30,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR)  #创建扭曲
    # image = image.transform((width+20,height+10), Image.AFFINE, (1,-0.3,0,-0.1,1,0),Image.BILINEAR)  #创建扭曲
    image = image.filter(ImageFilter.EDGE_ENHANCE_MORE) #滤镜,边界加强
    # image = image.filter(ImageFilter.EDGE_ENHANCE_MORE)  # 滤镜,边界加强
    bytes = BytesIO() # 内存
    image.save(bytes,format='png')  # 保存验证码图片

    return bytes.getvalue(),text # 获得二进制数据,

views

# netshop\userapp\views.py
from django.shortcuts import render,HttpResponse,redirect
from django.views import View
from userapp.models import *
import jsonpickle
from utils.code import gene_text

# 加载验证码
def loadCode(request):
    from captcha.image import ImageCaptcha
    image = ImageCaptcha()
    # 获取生成验证码字符串
    code = gene_text()
    imageObj = image.generate(code)
    # 返回图片
    return HttpResponse(imageObj, content_type='image/png')

templates修改

<input type="text" style="height:36px;width: 100px;" id="code" onblur="checkCode(this.value)"><img src="/userapp/loadCode/" onclick="changeCode(this)"><span style="color:red;" id="cSpan"></span>
//切换验证码
    function changeCode(obj) {
        $(obj).attr('src', '/userapp/loadCode/?r=' + new Date().getTime())
    }

在这里插入图片描述

1.3 校验输入的验证码是否正确

1.3.1如何实现验证验证码是否正确(前后端)

将正确的验证码存储到session中。我们在视图函数中编写一个验证功能,获取session中的验证码和输入框填写的验证码,验证后返回布尔值。
在前端的图片后,显示正确or错误,放一个onblur标签,调用前端的函数,前端函数的作用就是利用ajax发送同步请求,调用后端的验证功能,如果验证结果通过显示正确,反之错误。
在这里插入图片描述
在这里插入图片描述

1.3.2 代码展示

views

# 加载验证码
def loadCode(request):
    from captcha.image import ImageCaptcha
    image = ImageCaptcha()
    # 获取生成验证码字符串
    code = gene_text()
    # 将code存放到session中
    request.session['session_code'] = code

    imageObj = image.generate(code)
    # 返回图片
    return HttpResponse(imageObj, content_type='image/png')


# 校验输入的验证码是否正确
def checkCode(request):
    # 获取输入的验证码
    code = request.GET.get('code',-1)
    print(code)
    print(type(code))
    # 获取session对象中保存的正确的验证码
    session_code = request.session.get('session_code',-2)
    print('session_code',session_code)
    print(type(session_code))
    # 判断是否相等
    vflag = False
    if code == session_code:
        vflag = True
    # 返回响应
    return JsonResponse({'vflag':vflag})

templates

function checkCode(txt) {
        var cflag = false;
        $.ajax({
            url: '/userapp/checkCode/',
            type: 'get',
            data: { 'code': txt },
            async: false,
            success: function (result) {
                var flag = result.vflag;
                if (flag) {
                    cflag = true;
                    $('#cSpan').text('√');
                } else {
                    $('#cSpan').text('×');
                }
            }
        })
        return cflag;
    }

1.4 验证通过访问登录视图

views

# netshop\userapp\views.py
from django.shortcuts import render,HttpResponse,redirect
from django.http import JsonResponse
from django.views import View
from userapp.models import *
import jsonpickle
from utils.code import gene_text
# Create your views here.
# 注册视图类
class Register(View):
    def get(self,request):
        # 跳转到注册页面
        return render(request, 'userapp/register.html')
    def post(self,request):
        # 完成注册
        # 1.获取表单数据
        uname = request.POST.get('account','')
        pwd = request.POST.get('password','')
        # 2.查询数据库是否已有该用户
        try:
            user = UserInfo.objects.get(uname=uname, pwd=pwd)
            return render(request,'userapp/register.html')
        except UserInfo.DoesNotExist:
            user = UserInfo.objects.create(uname=uname, pwd=pwd)
            request.session['user'] = jsonpickle.dumps(user) # 把用户对象序列化为字符串
        return redirect('/userapp/center/') # 重定向到用户中心(路由地址)

# 用户中心
def userCenter(request):
    return render(request, 'userapp/center.html')

# 用户登录
class LoginView(View):
    def get(self,request):
        return render(request, 'userapp/login.html')
    def post(self, request):
        # 获取请求参数
        uname = request.POST.get('account','')
        pwd = request.POST.get('password','')
        # 根据输入的账户和密码查询数据是否存在该用户
        user = UserInfo.objects.filter(uname=uname, pwd=pwd)[0]
        # 如果有该用户,将用户存储到session种,跳转到个人页面;否则跳转到登陆页面
        if user:
            request.session['user'] = jsonpickle.dumps(user) # 把用户对象序列化为字符串
            return redirect('/userapp/center/')
        return redirect('/userapp/login/')
# 加载验证码
def loadCode(request):
    from captcha.image import ImageCaptcha
    image = ImageCaptcha()
    # 获取生成验证码字符串
    code = gene_text()
    # 将code存放到session中
    request.session['session_code'] = code

    imageObj = image.generate(code)
    # 返回图片
    return HttpResponse(imageObj, content_type='image/png')


# 校验输入的验证码是否正确
def checkCode(request):
    # 获取输入的验证码
    code = request.GET.get('code',-1)
    print(code)
    print(type(code))
    # 获取session对象中保存的正确的验证码
    session_code = request.session.get('session_code',-2)
    print('session_code',session_code)
    print(type(session_code))
    # 判断是否相等
    vflag = False
    if code == session_code:
        vflag = True
    # 返回响应
    return JsonResponse({'vflag':vflag})

templates

<!-- netshop\userapp\templates\userapp\login.html -->
{% extends 'base.html' %}
{% block title %}用户登录页面{% endblock %}

{% load static %}
{% block headerjs %}
<script type="text/javascript" src="{% static 'js/md5-min.js' %}"></script>
{% endblock %}

{% block main %}
<div class="login-body">
    <div class="login-card">
        <div class="login-top">
            <h3>新用户登录</h3>
            <h5>尊敬的用户,欢迎您回来!</h5>
        </div>
        <div class="login-bottom">
            <form method="post" action="/userapp/login/" onsubmit="return login();">
                <input type="hidden" name="time" id="time">
                <div class="login-input-box">
                    {% csrf_token %}
                    <input type="text" id="account" name="account" value="" class="login-admin active"
                        placeholder="邮箱登录">
                    <span style="color:red;" id="aSpan"></span>

                    <input type="password" id="password" name="password" value="" class="login-password">
                    <span style="color:red;" id="pSpan"></span>

                    <input type="text" style="height:36px;width: 100px;" id="code" onblur="checkCode(this.value)"><img src="/userapp/loadCode/" onclick="changeCode(this)"><span style="color:red;" id="cSpan"></span>

                    <input type="hidden" name="redirect" value="">
                    <input type="hidden" name="cartitems" value="None">

                    <button class="login-btn" style="color: white;text-decoration: none;cursor: pointer">登录</button>
                </div>
            </form>
            <div class="login-img">
                <img src="{% static 'images/login_05.png' %}" alt="">
            </div>
        </div>
    </div>
</div>

{% endblock %}

{% block footerjs %}
<script>
    function isEmail(str) {
        var reg = /^[a-zA-Z0-9_-]{6,}@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/;
        return reg.test(str);
    }

    function login() {
        //获取输入框的值
        var account = $('#account').val();
        var password = $('#password').val();
        var flag = true;
        //简单校验
        if (account.length < 6 || !isEmail(account)) {
            $('#aSpan').text('邮箱格式不正确');
            flag = false;
        }

        if (password.length < 6) {
            $('#pSpan').text('密码长度不能小于六位');
            flag = false;
        }

        var code = $('#code').val();
        var cflag = checkCode(code);

        if (!cflag) {
            $('#cSpan').text('×');
            return false;
        }

        if(!flag){
            return false;
        }

        var hex_pwd = hex_md5(password);

        //var hex_pwd = hex_md5(password+time)
        $('#password').val(hex_pwd);
        return true

    }


    //切换验证码
    function changeCode(obj) {
        $(obj).attr('src', '/userapp/loadCode/?r=' + new Date().getTime())
    }


    function checkCode(txt) {
        var cflag = false;
        $.ajax({
            url: '/userapp/checkCode/',
            type: 'get',
            data: { 'code': txt },
            async: false,
            success: function (result) {
                var flag = result.vflag;
                if (flag) {
                    cflag = true;
                    $('#cSpan').text('√');
                } else {
                    $('#cSpan').text('×');
                }
            }
        })
        return cflag;
    }
</script>
{% endblock %}

urls.py

# netshop\userapp\urls.py
from django.contrib import admin
from django.urls import path,include
from userapp import views
urlpatterns = [
    path('register/',views.Register.as_view()),
    path('center/',views.userCenter),
    path('login/',views.LoginView.as_view()),
    path('loadCode/',views.loadCode),
    path('checkCode/',views.checkCode),
]