验证码原理与Django实现--简陋滑块验证码

目录

前言

图片与滑块的生成和参数传递

前端展示

 误区

总结 


前言

随着验证码的发展,通过滑动滑块进行验证在许多网页有着应用

 不难看出其由图片及滑块组成,滑块从图片中截取。将其简化,就是一个大的图片和一个小的图片,通过移动小的图片以达到重合的目的。当然这是简陋版。


图片与滑块的生成和参数传递

图片和滑块的生成同样使用PIL库中的类实现,在生成图片时需要在随机的位置留下空白作为缺失的部分。为了更加简单和直观,滑块的边框采用方形,图片与滑块则只有颜色的区别。当然,最为重要的是缺失部分参数的保存与传递,其参数不仅用于前端页面滑块位置的渲染,也用于滑块最终重合与否。具体实现如下:

def slider(request):
    # 由于需要y对滑块位置进行确定,所以在此处将y赋值
    y = random.randint(15, 230)
    request.session['y'] = y
    # 只有完成滑动后才会进行获取并判断
    if request.method == 'POST':
        x = request.session.get('x') + 150
        final_x = int(request.POST.get('final_x'))
        # 平行滑动,只判断x轴,设置合理范围
        if final_x in range(x-3, x+4):
            return JsonResponse({'info': 1})
        else:
            return JsonResponse({'info': 0})
    return render(request, 'slider.html', {'y': y})


# 完整的图片生成
def complete_puzzle(request):
    # 初始化图片
    img_obj = Image.new('RGB', size=(500, 300), color='black')
    # 画笔初始化
    img_draw = ImageDraw.Draw(im=img_obj)
    # 划定图片残缺的范围,后续代码需要该参数以确保 残缺部分初始位置的正确,验证重合时的范围控制合理
    x = random.randint(20, 390)
    y = request.session.get('y')
    # 将数据存储在session中
    request.session.update({'x': x})
    # 正方形,规定左上及右下
    img_draw.rectangle(xy=[(x, y), (x+45, y+45)], fill='hotpink', width=2)
    # 临时存储
    io_obj = BytesIO()
    img_obj.save(io_obj, 'png')
    return HttpResponse(io_obj.getvalue())


# 滑动图片生成
def incomplete_puzzle(request):
    img_obj = Image.new('RGB', size=(45, 45), color='skyblue')
    io_obj = BytesIO()
    img_obj.save(io_obj, 'png')
    return HttpResponse(io_obj.getvalue())

前端展示

前端页面主要是获取y值,保证滑块与空缺位置平行

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>滑块验证</title>
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap-3.4.1-dist/css/bootstrap.min.css' %}">
    <script src="{% static 'js/jquery-3.6.0.min.js' %}"></script>
    <script src="{% static 'bootstrap-3.4.1-dist/js/bootstrap.min.js' %}"></script>
    <style>
        #container {
            height: 300px;
            width: 800px;
            margin: auto;
            position: relative;
        }
        .movable_image {
            position: absolute;
            transition: transform 0.1s ease;
        }
    </style>
</head>
<body>
    <h1 style="text-align: center">请滑动滑块使图片完整</h1>
    <div style="text-align: center;height: 300px;">
        <div class="container">
            <div class="row">
                <div class="col-md-12">
                    <div id="container">
                        <span style="display: inline-block;margin-right: 0">
                            <img src="/picture/complete_puzzle/">
                        </span>

                        <span style="top: {{ y }}px; left: 0;position: absolute">
                            <img src="/picture/incomplete_puzzle/" class="movable_image">
                        </span>
                    </div>
                </div>
            </div>
            <div class="row"  style="width: 300px; margin: auto">
                <div class="col-md-12" method="post">
                    <p>使用滑动条控制图片的横移:</p>
                    <input type="range" min="0" max="600" value="0" class="custom-range" id="slider">
                    <button type="button" id="id_button" class="btn btn-success">刷新</button>
                </div>
            </div>
        </div>
    </div>

    <script>
        $('#id_button').click(function () {
            location.reload();
        });
        $(document).ready(function() {
            $('#slider').on('input', function() {
                let value = $(this).val();
                $('.movable_image').css('transform', 'translateX(' + value + 'px)');
            });
        });
        $('#slider').one('mouseup', function() {
            let value = $(this).val();
            $.ajax({
                type: 'POST',
                data: {
                    'final_x': value,
                },
                success: function(args) {
                    if (args.info === 1) {
                        alert('成功');
                    } else{
                        alert('失败');
                    }
                }
            });
            // 禁用滑动条
            $('#slider').prop('disabled', true);
        });
    </script>
</body>
</html>

效果如下:


 误区

个人在views中写图片生成函数时,容易出现以下情况:

def slider(request):
    y = request.session.get('y')
    ...
    return render(request, 'slider.html', {'y': y})

# 完整的图片生成
def complete_puzzle(request):
    ...
    x = random.randint(20, 390)
    y = random.randint(15, 230)
    # 将数据存储在session中
    request.session.update({'x': x, 'y': y})
    ...

这是非常自然的思路,将x,y的随机整合到图片生成函数中去。但是大家在执行时就会发现滑块与空缺部分不在一条直线上

 于是我在函数中输出y值,发现:

也就是说,slider函数中的y值总是上一次 complete_puzzle函数中生成的值

 从控制台的输出也可以看出,先执行slider函数(先拿到y值),再执行complete_puzzle函数(设置y值),这就造成了slider函数传给前端的值是上一次的。找到原因后,就对症下药,将y的赋值放到slider函数中,即可解决。


总结 

 编程需要动手实践,看着简单,但是实操时就可能会出现报错,同时细节也非常重要。

不足请指正

  • 26
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值