H5 滑块拼图验证

1 篇文章 0 订阅

展示效果

参考视频地址
https://www.bilibili.com/video/BV1NM4y1g7S6

逻辑概述

使用背景图片的继承父节点样式的三张图片,子节点通过使用clip-path裁切图片,通过位置偏移来达成移动效果。

主要代码

布局

<div id="captcha">
    <div id="handle">
        <span></span>
    </div>
</div>

样式

 #captcha {
     display: block;
     width: var(--width);
     height: var(--height);
     border-radius: 4px;
     background-image: url(https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2676921178,3792372773&fm=55&app=54&f=JPEG?w=1680&h=630);
     background-size: cover;
     background-position: center;
     box-shadow: 0 2px 4px rgba(0, 0, 0, .3);
     position: relative;
     box-sizing: border-box;
}


#captcha::before,
#captcha::after {
    position: absolute;
    content: "";
    display: block;
    width: inherit;
    height: inherit;
    background-image: inherit;
    background-size: inherit;
    background-position: inherit;
    clip-path: var(--clip-path);
    --webkit-clip-path: var(--clip-path);
}

#captcha::after {
    transform: translateX(calc(var(--clip-offsetX) * -1 + var(--moved)));
    transition: .25s all ease-in-out;
}

#captcha::before {
    background-color: rgba(0, 0, 0, .5);
    background-blend-mode: multiply;
}

#captcha:active #handle span,
#captcha:active::after {
    transition: none;
}

#captcha #handle {
    width: calc(var(--width) - (3px * 2));
    height: 30px;
    border-radius: 18px;
    background-color: #eee;
    position: absolute;
    bottom: -50px;
    left: 0;
    box-shadow: inset 0 0 12px rgba(0, 0, 0, .2);
    border: 3px solid #ccc;
}

#handle span {
    display: block;
    width: var(--puzzle-width);
    height: inherit;
    border-radius: inherit;
    background-color: #fff;
    box-shadow: inset 0 0 6px rgba(0, 0, 0, .25), 0 2px 4px rgba(0, 0, 0, .3);
    position: absolute;
    cursor: move;
    transform: translateX(var(--moved));
    transition: .25s all ease-in-out;
}

#captcha.passed #handle,
#captcha.passed::after,
#captcha.passed::before {
    opacity: 0;
}

控制

let width = 400;        // 宽度
let height = 260;       // 高度
let puzzleWidth = 80;   // 切图宽
let puzzleHeight = 80;  // 切图高
let moved = 0;          // 移动位置
let mpe = 5;            // 允许最大误差
let offsetX = 6;        // 边距值  
let offsetY = 0;        // 边距值 
let shouldMove = false;

let clipRectX1 = randomRange(puzzleWidth + offsetX, width - puzzleWidth - offsetX);
let clipRectX2 = clipRectX1 + puzzleWidth;
let clipRectY1 = randomRange(puzzleHeight + offsetX, height - puzzleHeight - offsetY);
let clipRectY2 = clipRectY1 + puzzleHeight;

let captcha = document.querySelector('#captcha');
let handle = document.querySelector('#handle');
let button = document.querySelector('#handle span');

button.addEventListener("mousedown", (e) => {
    shouldMove = true;
})

window.addEventListener("mousemove", (e) => {
    if (shouldMove) {
        const offsetLeft = handle.getBoundingClientRect().left;
        const buttonWidth = button.getBoundingClientRect().width;
        moved = e.clientX - offsetLeft - buttonWidth / 2;
        render();
    }
})

window.addEventListener("mouseup", (e) => {
    if (shouldMove) {
        const finalOffset = e.clientX - handle.getBoundingClientRect().left - puzzleWidth / 2;
        if (Math.abs(finalOffset - clipRectX1) < mpe) captcha.classList.add('passed')
        else moved = 0;
        render();
        shouldMove = false;
    }
})

/**
 * 超出省略
 */
function clamp(num, a, b) {
    return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
}

/**
 * 随机数字
 */
function randomRange(min, max) {
    return Math.round(Math.random() * (max - min)) + min
}

/**
 *  渲染
 */
function render() {
    let clipPath = `polygon( ${clipRectX1}px ${clipRectY1}px, ${clipRectX2}px ${clipRectY1}px, ${clipRectX2}px ${clipRectY2}px, ${clipRectX1}px ${clipRectY2}px )`;
    captcha.style = `--clip-offsetX:${clipRectX1}px;--moved:${clamp(moved, 0, width - puzzleWidth - offsetX)}px;--clip-path:${clipPath};--width:${width}px;--height:${height}px;--puzzle-width:${puzzleWidth}px;--puzzle-height:${puzzleHeight}px`;
}

render();

完整代码

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            min-height: 100vh;
        }

        #captcha {
            display: block;
            width: var(--width);
            height: var(--height);
            border-radius: 4px;
            background-image: url(https://dss1.baidu.com/6ONXsjip0QIZ8tyhnq/it/u=2676921178,3792372773&fm=55&app=54&f=JPEG?w=1680&h=630);
            background-size: cover;
            background-position: center;
            box-shadow: 0 2px 4px rgba(0, 0, 0, .3);
            position: relative;
            box-sizing: border-box;
        }


        #captcha::before,
        #captcha::after {
            position: absolute;
            content: "";
            display: block;
            width: inherit;
            height: inherit;
            background-image: inherit;
            background-size: inherit;
            background-position: inherit;
            clip-path: var(--clip-path);
            --webkit-clip-path: var(--clip-path);
        }

        #captcha::after {
            transform: translateX(calc(var(--clip-offsetX) * -1 + var(--moved)));
            transition: .25s all ease-in-out;
        }

        #captcha::before {
            background-color: rgba(0, 0, 0, .5);
            background-blend-mode: multiply;
        }

        #captcha:active #handle span,
        #captcha:active::after {
            transition: none;
        }

        #captcha #handle {
            width: calc(var(--width) - (3px * 2));
            height: 30px;
            border-radius: 18px;
            background-color: #eee;
            position: absolute;
            bottom: -50px;
            left: 0;
            box-shadow: inset 0 0 12px rgba(0, 0, 0, .2);
            border: 3px solid #ccc;
        }

        #handle span {
            display: block;
            width: var(--puzzle-width);
            height: inherit;
            border-radius: inherit;
            background-color: #fff;
            box-shadow: inset 0 0 6px rgba(0, 0, 0, .25), 0 2px 4px rgba(0, 0, 0, .3);
            position: absolute;
            cursor: move;
            transform: translateX(var(--moved));
            transition: .25s all ease-in-out;
        }

        #captcha.passed #handle,
        #captcha.passed::after,
        #captcha.passed::before {
            opacity: 0;
        }
    </style>
</head>

<body>
    <div id="captcha">
        <div id="handle">
            <span></span>
        </div>
    </div>
    <script>
        let width = 400;        // 宽度
        let height = 260;       // 高度
        let puzzleWidth = 80;   // 切图宽
        let puzzleHeight = 80;  // 切图高
        let moved = 0;          // 移动位置
        let mpe = 5;            // 允许最大误差
        let offsetX = 6;        // 边距值  
        let offsetY = 0;        // 边距值 
        let shouldMove = false;
        
        let clipRectX1 = randomRange(puzzleWidth + offsetX, width - puzzleWidth - offsetX);
        let clipRectX2 = clipRectX1 + puzzleWidth;
        let clipRectY1 = randomRange(puzzleHeight + offsetX, height - puzzleHeight - offsetY);
        let clipRectY2 = clipRectY1 + puzzleHeight;

        let captcha = document.querySelector('#captcha');
        let handle = document.querySelector('#handle');
        let button = document.querySelector('#handle span');

        button.addEventListener("mousedown", (e) => {
            shouldMove = true;
        })

        window.addEventListener("mousemove", (e) => {
            if (shouldMove) {
                const offsetLeft = handle.getBoundingClientRect().left;
                const buttonWidth = button.getBoundingClientRect().width;
                moved = e.clientX - offsetLeft - buttonWidth / 2;
                render();
            }
        })

        window.addEventListener("mouseup", (e) => {
            if (shouldMove) {
                const finalOffset = e.clientX - handle.getBoundingClientRect().left - puzzleWidth / 2;
                if (Math.abs(finalOffset - clipRectX1) < mpe) captcha.classList.add('passed')
                else moved = 0;
                render();
                shouldMove = false;
            }
        })

        /**
         * 超出省略
         */
        function clamp(num, a, b) {
            return Math.max(Math.min(num, Math.max(a, b)), Math.min(a, b))
        }

        /**
         * 随机数字
         */
        function randomRange(min, max) {
            return Math.round(Math.random() * (max - min)) + min
        }

        /**
         *  渲染
         */
        function render() {
            let clipPath = `polygon( ${clipRectX1}px ${clipRectY1}px, ${clipRectX2}px ${clipRectY1}px, ${clipRectX2}px ${clipRectY2}px, ${clipRectX1}px ${clipRectY2}px )`;
            captcha.style = `--clip-offsetX:${clipRectX1}px;--moved:${clamp(moved, 0, width - puzzleWidth - offsetX)}px;--clip-path:${clipPath};--width:${width}px;--height:${height}px;--puzzle-width:${puzzleWidth}px;--puzzle-height:${puzzleHeight}px`;
        }

        render();
    </script>
</body>

</html>
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
根据提供的引用内容,美团验证的js逆向过程如下所示: 1. 首先,需要获取主页接口的参数,包括csrf、uuid、token_id和continues等。这些参数可以在第一个链接返回的源码中找到。 2. 接下来,使用这些参数进行登入接口的请求,其中包括两个加密参数password和h5Fingerprint。 3. 然后,通过验证码获取的接口来获取验证码相关的参数,如verifyMethodVersion、slider、yodaVersion、timestamp、sign、ses和requestCode等。 4. 在获取到这些参数后,可以进行验证接口的请求。该请求需要使用到加密参数behavior和_token,以及动态参数v_c和3eac9809,同时还需要在请求头中添加Authencation。 总结起来,美团验证的逆向过程可分为以下步骤: 1. 获取主页参数 2. 逆向pwd和h5Fingerprint 3. 请求page_data链接 4. 逆向Authencation、behavior和_token 5. 发起最终的验证请求 需要注意的是,以上仅是根据提供的引用内容进行的分析,具体的逆向过程可能还需要进一步的研究和分析。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* [【2023-03-10】JS逆向之美团块](https://blog.csdn.net/qq_26079939/article/details/129442967)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *3* [美团块(1-18,js逆向)](https://blog.csdn.net/weixin_44772112/article/details/128721509)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林一怂儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值