Vue+element登录页面实现拼图验证

  • 需求分析
  • 一、导入
  • 二、验证的意义
  • 三、常规验证手段
  • 详细设计
  • 一、使用组件
  • 二、轮子已找好,开始拼凑
  • 效果展示
  • 结尾


需求分析

一、导入

       项目开发过程中,遇到过一个简单的需求,即登录界面的 验证操作

       登录流程如下:

iOS 拼图验证 开发 拼图验证有什么意义_vue.js

二、验证的意义

       为什么会需要验证呢?其中一个重要的作用就是防止用户利用机器人自动注册、登录、灌水。

       验证码的出现是为了提高攻击者的付出成本。尽管现在的爬虫对于简单的验证已经能够绕过,但是依旧需要抓取登录界面的信息来模拟,需要一定的攻击成本。而此时后端的登录验证框架就显得尤为重要了。当然这是后话。

三、常规验证手段

       目前常规的前端界面验证手段有如下几种:

  1. 字符验证:根据图片中的字母或数字,填写验证。
  2. 运算验证:根据运算表达式,填写答案验证
  3. 拼图验证:根据图片上截取的缺口,滑动图片到缺口位置,判断是否匹配,完成验证。
  4. 选字验证:以B站登录界面弹出的选字验证为例。
  5. 选图验证:如12306上面的验证,根据提示的类型,如选出下面包含自行车的图片等。

具体样式可查看 前端验证码

详细设计

        在常规验证手段中,字符验证运算验证干扰程度低,且拉低审美。选取方案中被首先排除。

        然后选字验证和选图验证过于复杂,对于一般的小型网站设计,完全没有必要!

        那么最后的幸运儿就是: 拼图验证

一、使用组件

        Vue框架的一大优点就是组件化设计思想,对于重复的元素可以提取成一个组件,然后按需引入或者全局注册。
       那么为贯彻迅儿的”拿来主义“,咱们也去搬一搬,找一找大佬已经设计好的拼图验证子组件吧。

       这儿是传送带: Vue拼图验证组件

       使用方法

  • npm i vue-puzzle-verification 安装组件
  • 在main.js中引用
import PuzzleVerification from 'vue-puzzle-verification'
// 使用封装的登录验证vue组件
Vue.use(PuzzleVerification);

二、轮子已找好,开始拼凑

首先,前端需要绘制出登录界面:

Login.vue

<template>
    <div id="login">
        <el-col :xs="24" :sm="24" :md="24" :lg="24" :xl="24">
            <el-form :model="loginForm" :rules="rules" class="login-container" size="medium" @keyup.enter.native="handleClick">
                <h3 class="login_title">用户登录</h3>
                <el-form-item prop="username" >
                    <el-input type="text" v-model="loginForm.username" autofocus ref="username"
                              auto-complete="off" placeholder="用户名/邮箱" prefix-icon="el-icon-user-solid" spellcheck="false">
                    </el-input>
                </el-form-item>
                <el-form-item prop="password">
                    <el-input type="password" v-model="loginForm.password" autofocus ref="password"
                              auto-complete="off" placeholder="密码" prefix-icon="el-icon-key" v-on:input="change">
                    </el-input>
                </el-form-item>
                <el-form-item style="width: 100%;">
                    <el-checkbox class="login_remember" v-model="checked" >
                        <span style="color: #409EFF">记住我</span>
                        <label style="color: #949493">不是自己电脑请勿勾选</label>
                    </el-checkbox>
                    <router-link to="resetPassword" style="float: right; text-decoration: none; color: #50b6ff">找回密码?</router-link>
                </el-form-item>
                <el-form-item style="width: 100%">
                    <el-button type="primary" class="button_login"   @click="handleClick()">登录</el-button>
                    <router-link to="register">
                        <el-button type="primary" class="button_register">注册</el-button>
                    </router-link>
                </el-form-item>
            </el-form>
        </el-col>
        <el-popover
            placement="bottom"
            trigger="click" style="opacity: 0.7">
            <template #reference>
                <!--滑动图片弹窗验证-->
                <PuzzleVerification v-model="isVerificationShow" :puzzleImgList="puzzleImgList" blockType="puzzle"
                                    :onSuccess="handleSuccess" :onError="handleError"/>
            </template>
        </el-popover>
        <p class="login-copyright">© 2020 lkq 版权所有</p>
    </div>
</template>

<script>
import PuzzleVerification from 'vue-puzzle-verification'
export default {
    components: {PuzzleVerification},
    name: 'Login',
    data() {
        return {
            isVerificationShow: false,
            rules: {
                username: [{required: true, message: '用户名或邮箱不能为空', trigger: 'change'}],
                password: [{required: true, message: '密码不能为空', trigger: 'change'}]
            },
            checked: true,
            loginForm: {
                username: '',
                password: ''
            },
            puzzleImgList: [
                require("../../assets/images/verify/1.jpg"),
                require("../../assets/images/verify/2.jpg"),
                require("../../assets/images/verify/3.jpg"),
                require("../../assets/images/verify/4.jpg"),
                require("../../assets/images/verify/5.jpg"),
                require("../../assets/images/verify/6.jpg"),
                require("../../assets/images/verify/7.jpg"),
                require("../../assets/images/verify/8.jpg"),
                require("../../assets/images/verify/9.jpg"),
                require("../../assets/images/verify/10.jpg"),
            ],
            isInput: false,
        }
    },
    methods: {
        handleSuccess() {
            // 验证通过后关闭图片验证
            this.isVerificationShow = false;
            // 将数据传送到后端验证
            console.log("验证成功")
            // 将数据传送到后端验证
            this.login()
        },
        handleError() {
            // 滑动验证失败
            console.log("验证失败")
        },
        handleClick() {
            if (this.loginForm.username === '' || this.loginForm.password === '') {
                // 点击登录时,如果用户名或者密码未输入,那么提醒用户输入
                if (this.loginForm.username === '') {
                    this.$message({
                        message: '警告, 用户名或邮箱未输入哦',
                        type: 'warning'
                    });
                    this.$refs.username.focus();
                }else {
                    this.$message({
                        message: '警告, 密码未输入呀',
                        type: 'warning'
                    });
                    this.$refs.password.focus();
                }
            }else {
                this.isVerificationShow = true;
            }
        },
        change() {
           // 如果监听到输入框发生变化,那么采用用户输入的密码
           this.isInput = true;
        },
    	login() {
    		//..,将数据传送给后端
    	}         
    }
}
</script>

<style scoped >
    @import "../../assets/css/login.css";
    
</style>

简单解释一下:

  • :model="loginForm" : 表单的数据对象。
  • :rules="rules : 表单验证规则。
  • @keyup.enter.natice="handleClick": enter键函数,用户输入数据后可以直接enter键,不一定要点击按钮。
  • 记住我:利用cookie来存储登录信息,不是重点。
  • 找回密码:利用邮箱找回密码,不是重点,下一趴再介绍吧。
  • el-popover : element中的弹出框,作为容器。
  • trigger=click: 触发方式,点击触发。
  • #reference : 触发 Popover 显示的 HTML 元素。
  • :puzzleImgList="puzzleImgList": 传入的拼图背景图片。
  • blockType:滑块的形状。

对应的Css样式

#login {
    background-image: url('../login_img.jpg');
    background-repeat: no-repeat;
    background-size: cover;
    height: 100%;
    width: 100%;
    position: fixed;
}
.login-container {
    border-radius: 15px;
    background-clip: padding-box;
    margin: 10% 40% 0 40%;
    width: 20%;
    padding: 25px 30px;
    background: #fff;
    border: 1px solid #eaeaea;
    box-shadow: 0 0 25px #cac6c6;
    opacity: 0.7;
}



.login_title {
    margin: 0px auto 40px auto;
    text-align: center;
    color: #505458;
}

.login_remember {
    margin: 0px;
    text-align: left;
    float: left;

}

.button_login {
    width: 40%;
    background: #409EFF;
    border: none;
    float: left
}

.button_register {
    width: 40%;
    background: #505458;
    border: none;
    float: right;
}

.login-copyright {
    color: #eee;
    padding-bottom: 20px;
    text-align: center;
    position: relative;
    z-index: 1;
}

@media screen and (min-height: 550px) {
    .login-copyright {
        position: absolute;
        bottom: 0;
        right: 0;
        left: 0;
    }
}

效果展示

登录界面:

iOS 拼图验证 开发 拼图验证有什么意义_vue.js_02

点击登录后:

iOS 拼图验证 开发 拼图验证有什么意义_vue.js_03


控制台查看回调函数:

iOS 拼图验证 开发 拼图验证有什么意义_html_04


这里是滑动成功后截屏,控制台还未输出。

结尾

又是一个安静的晚上,一个人窝在摇椅里乘凉!