BBS

 

  基于用户认证组件和Ajax实现登录验证(图片验证码)

  UserInfo表既有原生auth_user表的字段,又有你扩展的字段,以后用的接口UserInfo既是自己的用户表又是原生认证组件的用户表

一.登录页面的设计

  login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css">
</head>
<body>

    <h3>登录页面</h3>

    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3" >
                <form>
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="user">用户名</label>
                        <input type="text" id="user" class="form-control">
                    </div>
                    <div class="form-group">
                        <label for="pwd">密码</label>
                        <input type="password" id="pwd" class="form-control">
                    </div>

                    <div class="form-group">
                        <label for="">验证码</label>
                        <div class="row">  {# 独立一行 #}
                            {# 各占一半 #}
                            <div class="col-md-6">
                                <input type="text" id = "valid_code" class="form-control">
                            </div>
                            <div class="col-md-6">
                                <img width="265" height="38" id="valid_code_img" src="/get_valid_img/" alt="">
                            </div>
                        </div>
                    </div>
                    <input type="button" class="btn btn-default login_btn " value="submit"><span class="error"></span>
                    <a href="/register/" class="btn btn-success pull-right">注册</a>
                </form>
            </div>
        </div>
    </div>

二.验证码图片的生成

  validCode.py

# -*- coding:utf-8 -*-
import random


def get_random_color(): # 生成随机颜色三要素
    return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))


def get_valid_code_img(request):

    # 方式一:写死了
    # with open("kobe.jpg", "rb") as f:
    #     data = f.read()
    # return HttpResponse(data)

    # 方式二:磁盘中 速度慢 # pip install pillow  # 图像处理模块
    # from PIL import Image
    # img = Image.new("RGB", (265, 38), color=get_random_color())  # Image.new(mode,size,color) 长度265 高度38
    #
    # # 生成随机图片
    # with open("validCode.png", "wb") as f: # 先加到磁盘上
    #     img.save(f, "png")  # 会生成一个叫validCode.png的图片
    #
    # # 读出图片
    # with open("validCode.png", "rb") as f:
    #     data = f.read()

    # 方式三:放在内存中
    # from PIL import Image
    # from io import BytesIO   # BytesIO就是内存管理
    # img = Image.new("RGB", (265, 38), color=get_random_color())  # Image.new(mode,size,color)
    #
    # f = BytesIO()  # 内存句柄
    # img.save(f, "png")  # save到内存中
    # data = f.getvalue()  # 读数据

    # 方式四:放在内存中, 添加文字
    from PIL import Image, ImageDraw, ImageFont  # ImageDraw是画笔,ImageFont是字体大小
    from io import BytesIO
    img = Image.new("RGB", (265, 38), color=get_random_color())  # Image.new(mode,size,color)

    draw = ImageDraw.Draw(img)  # 在img中画东西,draw.text()写文字,draw.line()画线,draw.point()画点
    kumo_font = ImageFont.truetype("static/fonts/KumoFont.ttf", size=30) # 参数为字体路径和大小

    # global valid_code_str
    valid_code_str = ""
    for i in range(6):
        random_num = str(random.randint(0, 9))
        random_low_alpha = chr(random.randint(97, 122))
        random_upper_alpha = chr(random.randint(65, 90))

        random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])

        # text(self, xy, text, fill=None, font=None, anchor=None,*args, **kwargs)
        # xy:坐标 text:文字 fill:颜色 font:字体
        draw.text(((30*i+45), 5), random_char, get_random_color(), font=kumo_font)

        # 保存验证码字符串
        valid_code_str += random_char

    f = BytesIO()  # 内存句柄
    img.save(f, "png")
    data = f.getvalue()  # 读数据

    return data

噪声噪线

  validCode.py

补充躁点躁线, 防止机器
    width = 265  # 要跟上边的宽高一致
    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(80):
        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())

三.验证码刷新

$("#valid_code_img")[0]
<img width=​"270" height=​"40" id=​"valid_code_img" src=​"http:​/​/​127.0.0.1:​8000/​get_validCode_img/​??" alt>​
 $("#valid_code_img")[0].src
"http://127.0.0.1:8000/get_validCode_img/??"

 $("#valid_code_img")[0].src+="?"  #+="?"添加一次这个就刷新一次验证码
"http://127.0.0.1:8000/get_validCode_img/???"
 $("#valid_code_img")[0].src+="?"
"http://127.0.0.1:8000/get_validCode_img/????"
 $("#valid_code_img")[0].src+="?"
"http://127.0.0.1:8000/get_validCode_img/?????"
 $("#valid_code_img")[0].src+="?"
"http://127.0.0.1:8000/get_validCode_img/??????"
 $("#valid_code_img")[0].src+="?"
"http://127.0.0.1:8000/get_validCode_img/???????"

  login.html

<script src="/static/js/jquery-3.3.1.js"></script>
    <script>
        {# 刷新验证码,不用ajax也可以 #}
        $("#valid_code_img").click(function () {
            $(this)[0].src += "?"
        });
    </script>

四.保存验证码字符串

   validCode.py

valid_code_str = "" #保存验证码字符串,这样才能验证
    for i in range(5):
        random_num = str(random.randint(0,9))
        random_low_alpha = chr(random.randint(95,122))
        random_upper_alpha = chr(random.randint(65,90))
        random_char = random.choice([random_num, random_low_alpha, random_upper_alpha])
        draw.text((i*50+20, 5), random_char, get_random_color(), font=kumo_font)

        #保存验证码字符串
        valid_code_str += random_char #做一个累加

    print("valid_code_str", valid_code_str)
    request.session["valid_code_str"] = valid_code_str  #保存它,写一个session

    '''
    1 sdajsdq33asdf #生成一个随机字符串,
    2 COOKIE {"sessionid":sdajsdq33asdf} #设置一个cookie,返回给cookie那边一个键叫sessionid,值是随机字符串
    3 django-session   #数据部分保存到了django_session;在session表进行存储
      session-key   session-data
      sdajsdq33asdf  {"valid_code_str":"12345"}
    '''

    f = BytesIO()
    img.save(f,"png")
    data = f.getvalue()

    return HttpResponse(data)

五.登录验证

#global valid_code_str 这里不能把它变成全局变量,这时虽然校验时可以拿到valid_code_str,但如果是两个人一块访问,那么那个验证码的值存的是最后一个人访问(刷新)的,前面那个人那个就取不到了应该每个人的单独保存,使用会话跟踪技术,把每个人校验的值存到cookie里边

  views.py

# -*- encoding:utf-8 -*-
from django.shortcuts import render, HttpResponse, redirect

import random
# Create your views here.
from django.http import JsonResponse
from django.contrib import auth

def login(request):

    if request.method == "POST":

        response = {"user": None, "msg": None} # 先构建一个字典,"user":None默认没有登录成功,"msg"里边放错误信息
        user = request.POST.get("user")
        pwd = request.POST.get("pwd")
        valid_code = request.POST.get("valid_code")

        # global valid_code_str,不能使用这种方法,因为当多个人同时登录的时候valid_code_str会被覆盖掉,会产生混淆
        # 使用会话跟踪技术,session来保存每个人的验证码,request.session["valid_code_str"] = valid_code_str
        valid_code_str = request.session.get("valid_code_str")
        if valid_code.upper() == valid_code_str.upper():    # 验证验证码,不区分大小写

            #  验证用户名密码
            user = auth.authenticate(username=user, password=pwd) # 用户认证组件
            if user:  # 把这个user注册进去,只要登录成功了,request.user就是当前登录对象用户,否则它就是个匿名对象
                auth.login(request, user)  # requese.user 当前登录对象,登录成功在这里不能跳转,用的是ajax请求而不是form请求,ajax请求只接收一个数据data
                response["user"] = user.username
            else:
                response["msg"] = "用户名或者密码错误!"
        else:
            response["msg"] = "验证码错误!"

        return JsonResponse(response) # 直接把字典放里面,它帮我们序列化,而且在ajax那边直接拿到对象也不用反序列化

    return render(request, 'login.html')

def index(request):

    return render(request, "index.html")

  login.html

{# ajax登录验证 #}
        $(".login_btn").click(function () {
            $.ajax({
                url:"",
                type:"post",
                data:{
                    user:$("#user").val(), {# 获取用户名输入数据 #}
                    pwd:$("#pwd").val(), {# 获取密码输入数据 #}
                    valid_code:$("#valid_code").val(), {# 获取验证码输入数据 #}
                    csrfmiddlewaretoken:$("[name='csrfmiddlewaretoken']").val()   {# 必须加这个键值对才能通过校验 #}
                },
                success:function (data) {
                    console.log(data);

                    if (data.user){  {# 判断有没有值,出错就把错误信息显示在页面上 #}
                        location.href = "/index/" {# 登录成功就跳转到index页面 #}
                    }
                    else {
                        $(".error").text(data.msg).css({"color": "red", "margin-left":"20px"})

                        {# 规定时间清空错误信息 #}
                        setTimeout(function () {
                            $(".error").text("")
                        }, 1000)
                    }
                }
            })
        })
总结:
1 一次请求伴随多次请求
2 PIL
3 session存储
4 验证码刷新

附:

滑动验证码--->引入这样一个插件

要先把social-auth-app-django下载下来

C:UsersAdministrator>pip install social-auth-app-django
Collecting social-auth-app-django

把它嵌入到我们的代码里边

原文地址:https://www.cnblogs.com/mumupa0824/p/10417819.html