滑块验证码 Django实现

目录

 

前言

后端

随机选取图片

截取图片

 判断部分

前端

展示滑块与图片,并监听滑动

效果展示

误区总结

错误:前端展示的图片与预期不同

解决尝试1:在前端限定图片大小

解决尝试2:后端resize出现问题 


前言


验证码原理与Django实现--简陋滑块验证码中所实现的滑块验证码是其最简单的一个实现,但是与大多数网页中的滑块验证码尚有出入。本文展示与网页接近的滑块验证码实现

27d8f960772748c4b059e7153d0f5187.jpeg

滑块验证码的组成无非是两部分:带空缺的图片和滑块(即与空缺相匹配的图片)。要实现滑块验证码就是要解决这两部分


后端

随机选取图片

首先从文件夹中随机取出一张图片,将图片的地址存储到session中(其他函数需要对该图片进行处理),然后通过随机数确定所截取图片的坐标(纵坐标y需要传给前端以保证截取部分与空缺部分平行)

def detail_puzzle(request):
    # 判断部分
    if request.method == 'POST':
        pass
    # 从文件夹中随机选取图片
    all_images = list(os.listdir('././static/imgs/slider'))
    image_url = random.choice(all_images)
    # 拼接完整地址
    image_url = os.path.join('././static/imgs/slider', image_url)
    # 将图片地址存储在session中
    request.session['image_url'] = image_url
    # 随机截取位置的x,y值(左上)
    # 由于需要y对滑块位置进行确定,所有在此处将y赋值
    x = random.randint(20, 390)
    y = random.randint(15, 230)
    request.session.update({'x': x, 'y': y})
    return render(request, 'detail_slider.html', locals())

截取图片

通过session取出xy值,截取图片的一部分,并对图片该部分进行暗化处理。将所截取的图片也返回前端(使用的方法没有改变原图大小,所以部分代码重复出现)

def complete_image(request):
    x = request.session.get('x')
    y = request.session.get('y')
    with Image.open(request.session.get('image_url')) as img_obj:
        # 改变图片大小
        # resize的返回值才是改变后的图片
        img_obj = img_obj.resize((500, 300))
        area = (x, y, x + 45, y + 45)
        # 截取范围
        darken_region = img_obj.crop(area)
        # 此处虽然将图片改为了规定大小,但是截取
        # 调整区域的亮度
        enhancer = ImageEnhance.Brightness(darken_region)
        darkened_region = enhancer.enhance(0.45)
        # 将变暗的区域黏贴回去
        img_obj.paste(darkened_region, area)
        # 主要用于展示原图
    io_obj = BytesIO()
    img_obj.save(io_obj, 'png')
    return HttpResponse(io_obj.getvalue())

def part_image(request):
    # 拿到x,y值
    x = request.session.get('x')
    y = request.session.get('y')
    # 划定范围
    crop_area = (x, y, x + 45, y + 45)
    # 获取图片地址
    image_path = request.session.get('image_url')
    # 打开图片
    with Image.open(image_path) as img_obj:
        # 改变图片大小
        img_obj = img_obj.resize((500, 300))
        # 截取指定区域
        cropped_img = img_obj.crop(crop_area)
    io_obj = BytesIO()
    cropped_img.save(io_obj, 'png')
    return HttpResponse(io_obj.getvalue())

 判断部分

 设置合理范围,对post请求返回的数据进行验证

def detail_puzzle(request):
    # 只有完成滑动后才会进行获取并判断
    if request.method == 'POST':
        x = int(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})
    # 随机选取图片部分
    pass

前端

展示滑块与图片,并监听滑动

 

<!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_image/">
                        </span>

                        <span style="top: {{ y }}px; left: 0;position: absolute">
                            <img src="/picture/part_image/" 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>

效果展示

88b7b80eecff4b97a0d2384e4bc6bb8b.png89e571337efd469986b6af3de73846b1.png 219a8366b9f143debd99c6ffe01d537b.png


误区总结

错误:前端展示的图片与预期不同

 1c04ea83409045889a83faf325c5de4e.png

很明显,图片超出了预期

96eb0f52b3c04b8c8600341797482948.png

 并且位置判断出现问题


解决尝试1:在前端限定图片大小

 在img中加上

style="width: 500px;height: 300px"

于是更加离谱

64180727154348519572c362443cdd47.png


解决尝试2:后端resize出现问题 

 可以观察到最初只有图片大小出现问题,而位置判断很可能是前者附带的。经过分析,发现最初resize的使用为:

    with Image.open(image_path) as img_obj:
        # 改变图片大小
        img_obj.resize((500, 300))

但是resize函数的返回值才是改变后的图片对象


大二在读,不足请指正

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值