zoukankan      html  css  js  c++  java
  • 博客园项目-登录(验证码,ajax提交数据,session和cookie)

    博客园项目-登录(验证码,ajax提交数据,session和cookie)

    前端页面

    复制代码
    {% load static %}
    <!DOCTYPE html>
    <html lang="zh-CN">
    <head>
        <meta charset="UTF-8">
        <meta http-equiv="x-ua-compatible" content="IE=edge">
        <meta name="viewport" content="width=device-width, initial-scale=1">
        <title>Title</title>
        <link rel="stylesheet" href="{% static 'bootstrap-3.3.7/css/bootstrap.min.css' %}">
        <style>
            body {
                background-color: #eeeeee;
            }
            h3{
                padding-left: 100px;
            }
            .container{
                margin-top: 300px;
            }
        </style>
    </head>
    <body>
    
    <div class="container">
        <div class="row">
            <div class="col-md-6 col-md-offset-3">
                <h3>请登录</h3>
                <form class="form-horizontal">
                    {% csrf_token %}
                    <div class="form-group">
                        <label for="inputUser" class="col-sm-2 control-label">账号</label>
                        <div class="col-sm-10">
                            <input type="text" class="form-control" id="inputUser" placeholder="账号">
                            <span class="help-block"></span>
                        </div>
                    </div>
                    <div class="form-group">
                        <label for="inputPassword" class="col-sm-2 control-label">密码</label>
                        <div class="col-sm-10">
                            <input type="password" class="form-control" id="inputPassword" placeholder="Password">
                            <span class="help-block"></span>
                        </div>
                    </div>
    
                    <div class="form-group">
                        <label for="valid_code" class="col-sm-2 control-label">验证码</label>
                        <div class="col-sm-5">
                            <input type="text" class="form-control" id="valid_code" placeholder="验证码">
                            <span class="help-block"></span>
                        </div>
                        <div class="col-sm-5">
                            <img src="/get_valid_img/" alt="" width="200" height="40">
                        </div>
                    </div>
    
                    <div class="form-group">
                        <div class="col-sm-offset-2 col-sm-10">
                            <input type="button" class="btn btn-primary btn-lg btn-block" value="登录">
                            <span></span>
                        </div>
                    </div>
                </form>
            </div>
        </div>
    </div>
    
    <script src="{% static 'jquery-3.2.1.min.js' %}"></script>
    <script src="{% static 'bootstrap-3.3.7/js/bootstrap.min.js' %}"></script>
    <script>
    
        $(":button").click(function () {
            $.ajax({
                url:"/login/",
                type:"post",
                data:{
                    "user":$("#inputUser").val(),
                    "pwd":$("#inputPassword").val(),
                    "valid_code": $("#valid_code").val(),
                    "csrfmiddlewaretoken":$("[name='csrfmiddlewaretoken']").val()
                },
                success: function (data) {
                    var data = JSON.parse(data);
                    if (data.is_login){
                        location.href="/index/"
                    }else{
                        $(":button").next().text(data.error_msg).css("color","red")
                        setTimeout(function () {
                            $(":button").next().text("")
                        },1000)
                    }
                }
            })
        })
    
    </script>
    </body>
    </html>
    复制代码

    可以看到用户访问登录页面时,在求情验证码图片时会访问/get_valid_img/,通过该url来得到验证码图片

    用户的数据通过ajax提交到后端,当后端完成验证后,如果验证成后,则跳转到首页,如果失败,则将错误信息添加到页面上

    生成随机验证码

    复制代码
    def get_valid_img(request):
        # from utils.random_code import get_random_code  # 局部模块导入不能用*
        # data = get_random_code()
        import random
    
        def get_random_color():
            return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
    
    
        # 方式1:
        # f = open("car.jpg", "rb")
        # data = f.read()
        # f.close()
    
        # 方式2:将图片存到磁盘
        # import PIL
        # from PIL import Image
        # from io import BytesIO
        # image = Image.new(mode="RGB", size=(120, 80), color=get_random_color())
        # f = open("code.png", "wb")
        # image.save(f, "png")
        # f.close()
        # f = open("code.png", "rb")
        # data = f.read()
        # f.close()
    
        # 方式3:将图片放到内存
        # import PIL
        # from PIL import Image
        # from io import BytesIO
        # image = Image.new(mode="RGB", size=(120, 80), color=get_random_color())
        # f = BytesIO()
        # image.save(f, "png")
        #
        # data = f.getvalue()
    
        # 方式4:
        from PIL import Image  # PIL模块可以通过下载pillow模块使用
        from io import BytesIO
        from PIL import ImageDraw, ImageFont  # 画笔
        image = Image.new(mode="RGB", size=(120, 80), color=get_random_color())
        draw = ImageDraw.Draw(image)
        font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)
        temp = []
        for i in range(5):
            random_char = random.choice(
                [chr(random.randint(65, 90)), chr(random.randint(97, 122)), str(random.randint(0, 9))])
            draw.text((i * 24, 20), random_char, get_random_color(), font=font)  # 参数分别为坐标,添加的字符串,颜色,字体
            temp.append(random_char)
            # 为了让生成的验证码更具迷惑性,我们可以使用下面的方法给验证码图片中增加随机的点线等
        # for i in range(80):
        #     draw.point((random.randint(0,width),random.randint(0,height)),fill=get_random_color())
        #
        # 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(40):
        #     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()
        image.save(f, "png")
    
        data = f.getvalue()
        # 保存随机字符串
        random_code_str = "".join(temp)
        request.session["random_code_str"] = random_code_str
        '''
        1 生成随机字符串
        2 响应set_cookie {"sessionid": "e21e12gg2d3sds"}
        3 在django_session表中插入一条记录
            session_key     session_data
        '''
    
        return HttpResponse(data)
    复制代码

    由于验证码需要生成图片,此处我们导入了PIL模块(用来生成图片的模块)

    先生成一个image对象,图片的颜色应该是随机的,我们定义一个生成3个随机数字组成元组的函数

    import random
    
        def get_random_color():
            return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))

    验证码中还需要有随机的字符串,此时我们从PIL模块中导入ImageDraw(画笔), ImageFont(字体)

    首先生成一个字体对象,要先下载字体文件,并存放到项目中

    然后通过该字体文件生成字体对象

    font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)  # size为字体大小

    然后往生成image图片中添加内容,内容应该为随机字符串,采用以下方法生成并添加到image图片中

    复制代码
    draw = ImageDraw.Draw(image)  # 画笔
    font = ImageFont.truetype("static/fonts/kumo.ttf", size=32)
    temp = []
    for i in range(5):
        random_char = random.choice(
            [chr(random.randint(65, 90)), chr(random.randint(97, 122)), str(random.randint(0, 9))])
        draw.text((i * 24, 20), random_char, get_random_color(), font=font)
        temp.append(random_char)
    复制代码

    由于验证码图片只是发送给用户用来验证用的,没有必要保存到本地磁盘中,我们可以从io模块中导入BytesIO,在内存中生成空间来存放图片

    from io import BytesIO
    f = BytesIO()
    image.save(f, "png")
    
    data = f.getvalue()

    此时将data返回给页面,用户就可以看到验证码图片了

    但是为了方便我们接收到用户输入的验证码后进行验证,我们需要保存此次生成验证码的内容

    # 保存随机字符串
    random_code_str = "".join(temp)

    现在我们需要考虑一个问题,用上面的方法保存验证码内容,如果一个用户先访问了登录页面,此时random_code_str被赋予了一个值,而这是另一个用户也访问了登录页面,这时random_code_str会被后一个值覆盖

    那么前一个用户输入正确的验证码也无法验证成功了

    在这种情况下,我们需要保证每一个用户都能保存住自己访问页面时验证码的值,可以考虑使用session

    # 保存随机字符串
    random_code_str = "".join(temp)
    request.session["random_code_str"] = random_code_str

    这里我们需要知道request.session做了什么:

    1 生成随机字符串
    2 响应set_cookie {"sessionid": "e21e12gg2d3sds"}
    3 在django_session表中插入一条记录

    如果用户访问时,已经有了cookie,那么这个操作会更新数据库django_session表中session_data的内容,而不会改变session_key等其它内容

    点击更新验证码

    当我们登录时,经常会遇到验证码看不清的情况,此时我们可以通过点击验证码图片进行刷新

    这个功能可以通过前端JS实现

        // 验证码刷新
        $("img").click(function () {
            $(this)[0].src += "?"
        })

    找到验证码图片的img标签,给他绑定一个点击事件,通过DOM对象的方法,在该图片的src后面加一个?号便可实现再次访问

    后端验证

    复制代码
    def log_in(request):
        response = {"is_login": False, "error_msg": ""}
        if request.method == "POST":
            username = request.POST.get("user")
            pwd = request.POST.get("pwd")
            valid_code = request.POST.get("valid_code")
            code_str = request.session.get("random_code_str")
            if valid_code.upper() == code_str.upper():
                user = auth.authenticate(username=username, password=pwd)
                if user:
                    response["is_login"] = True
                    auth.login(request, user)  # 1 {"user_id": 1} 2 request.user=user
                else:
                    response["error_msg"] = "用户名密码错误"
            else:
                response["error_msg"] = "验证码错误"
            return HttpResponse(json.dumps(response))
        return render(request, "login.html")
    复制代码

    我们先校验验证码是否正确,在验证码正确的前提下再使用auth组件进行用户名和密码的验证

    需要注意,当用户名密码也验证成功后,我们使用auth.login()方法写session,但由于此前访问验证码图片时已经在数据库中生成了session记录,该方法会先flush清除记录,再添加新的记录

    所以这时我们会看到cookie中的sessionid的值变了,这里要和生成验证码时使用的request.session方法区分开来

  • 相关阅读:
    OpenStack 数据库操作 demo
    python 实现获取电脑IP、主机名、Mac地址
    openvswitch BFD 简介
    Python 获取主机名
    OpenvSwitch完全使用手册
    ovs datapath笔记
    openstack 实用命令
    表示数值的字符串 牛客网 剑指Offer
    反转单词顺序列 牛客网 剑指Offer
    第一个只出现一次字符的位置 牛客网 剑指Offer
  • 原文地址:https://www.cnblogs.com/QQ279366/p/8424224.html
Copyright © 2011-2022 走看看