验证码(一)快速使用文本验证码.

文本验证码

        用户需要识别并输入图片中显示的随机字符或数字组合,通常用于验证用户是人类而非自动化程序。

优点

        实现简单:技术难度较低,容易在各种网站和应用中部署。

        兼容性好:几乎所有的设备和浏览器都能支持,无需额外的插件或特殊设置。

缺点

        易被破解:随着图像识别技术的发展,一些自动化程序能够较容易地识别和破解简单的文本验证码。

        用户体验差:对于视力不好或有阅读障碍的用户来说,识别扭曲、模糊的字符可能会有困难,影响使用体验。

1.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
    <meta http-equiv="Access-Control-Allow-Origin" content="*">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta name="apple-mobile-web-app-status-bar-style" content="black">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    <meta name="format-detection" content="telephone=no">
    <link rel="stylesheet" href="/static/lib/layui/css/layui.css" media="all">
    <link rel="stylesheet" href="/static/css/verify.css" media="all">
</head>
<body>
<div class="layui-container">
    <div class="admin-login-background">
        <div class="layui-form login-form">
            <form class="layui-form" action="">
                <div class="layui-form-item logo-title">
                    <h1>文本验证码演示</h1>
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-username"></label>
                    <input type="text" name="uname" maxlength="11" lay-verify="required" placeholder="用户名或者手机号"
                           autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-password"></label>
                    <input type="password" name="ipassword" maxlength="20" lay-verify="password" placeholder="密码"
                           autocomplete="off" class="layui-input" value="">
                </div>
                <div class="layui-form-item">
                    <label class="layui-icon layui-icon-vercode"></label>
                    <input type="text" id="captcha" name="captcha" lay-verify="captcha" placeholder="图形验证码"
                           autocomplete="off" class="layui-input verification captcha" value="" maxlength="5">
                    <div class="captcha-img">
                        <img id="captchaPic" src="/api/v1/verify/getTextVerify">
                    </div>
                </div>
                <div class="layui-form-item">
                    <button type="button" id="submitBtn" class="layui-btn layui-btn layui-btn-normal layui-btn-fluid"
                            lay-submit="" lay-filter="login">登 录
                    </button>
                </div>
            </form>
        </div>
    </div>
</div>
<script src="/static/lib/jquery/jquery.min.js" charset="utf-8"></script>
<script src="/static/lib/layui/layui.js" charset="utf-8"></script>
<script src="/static/js/ajax.js"></script>
<script src="/static/api/text_verify.js"></script>
</body>
</html>

2.verify.css

html, body {
    width: 100%;
    height: 100%;
    overflow: hidden;
}
body {
    background-image: url("/static/images/loginbg.png");
    background-size: cover;
}
.layui-container {
    width: 100%;
    height: 100%;
    overflow: hidden;
    background-image: url("/static/images/loginbg.png");
    background-repeat: repeat;
}
.admin-login-background {
    z-index: 99999;
    width: 500px;
    height: 350px;
    position: fixed;
    top: 0px;
    left: 0px;
    right: 0px;
    bottom: 200px;
    margin: auto;
}
.logo-title {
    text-align: center;
    letter-spacing: 2px;
    padding: 14px 0;
}
.logo-title h1 {
    color: #1E9FFF;
    font-size: 25px;
    font-weight: bold;
}
.login-form {
    background-color: #fff;
    border: 1px solid #fff;
    border-radius: 3px;
    padding: 14px 20px;
    box-shadow: 0 0 8px #eeeeee;;
    width: 500px;
    height: 350px;
    position: absolute;
    top: 0;
    left: 0;
    bottom: 0;
    right: 0;
    margin: auto;
}
.login-form .layui-form-item {
    position: relative;
}
.login-form .layui-form-item label {
    position: absolute;
    left: 1px;
    top: 1px;
    width: 38px;
    line-height: 36px;
    text-align: center;
    color: #d2d2d2;
}
.login-form .layui-form-item input {
    padding-left: 36px;
    font-size: 15px;
}
.captcha {
    width: 66%;
    display: inline-block;
}
.captcha-img {
    display: inline-block;
    width: 158px;
    float: right;
    margin-right: 3px;
}
.captcha-img img {
    height: 34px;
    border: 1px solid #e6e6e6;
    height: 36px;
    width: 100%;
    cursor: pointer
}
.copyright {
    text-align: center;
    color: #1E9FFF;
    line-height: 50px;
}

text_verify.js
layui.use(['form'], function () {
    var form = layui.form;
    var layer = layui.layer;
    var setter = layui.setter;
    var iphone_reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;//包含最新手机号码的正则表达式验证
    var pass_reg = /^\w+$/;//由数字、26个英文字母或者下划线组成的8位以上字符串
    var base_reg = /^[A-Za-z0-9]+$/;//字母和数字
    // 登录过期的时候,跳出ifram框架
    if (top.location !== self.location) top.location = self.location;
    //文本框回车提交
    $(".layui-input").keydown(function (e) {
        if (e.keyCode === 13) {
            $("#submitBtn").trigger("click");
        }
    });
    form.verify({
        account: function (values) {
            if (!iphone_reg.test(values)) {
                return "请使用手机号码进行登录";
            }
        },
        password: function (values) {
            if (!pass_reg.test(values)) {
                return "必须包含大小写字母和数字的组合,不能使用特殊字符,长度不小于8位";
            }
        },
        captcha: function (values) {
            if (values.length !== 5) {
                return "请输入5位长度的验证码";
            }
            if (!base_reg.test(values)) {
                return "请输入5位长度的验证码";
            }
        }
    })
    $("#captchaPic").click(function () {
        $(this).attr("src", "/api/v1/verify/getTextVerify?t=" + Math.random());
    })
    // 进行登录操作
    form.on('submit(login)', function (data) {
        var td = data.field;
        ajax.request({
            method: "/user/doTextVerifyLogin",
            type: "post",
            callback: function (res) {
                layer.msg(res.msg, {icon: res.code === 0 ? 1 : 5, time: 1000}, function () {
                    if (res.code === 0) {
                        layui.data("webapp", {
                            key: "data",
                            value: res.data
                        });
                    } else {
                        $("#captcha").val("");
                        $("#captchaPic").trigger("click");
                    }
                });
            }
        }, td);
        return false;
    });
});

3.text_verify.js 

layui.use(['form'], function () {
    var form = layui.form;
    var layer = layui.layer;
    var setter = layui.setter;
    var iphone_reg = /^(13[0-9]|14[01456879]|15[0-35-9]|16[2567]|17[0-8]|18[0-9]|19[0-35-9])\d{8}$/;//包含最新手机号码的正则表达式验证
    var pass_reg = /^\w+$/;//由数字、26个英文字母或者下划线组成的8位以上字符串
    var base_reg = /^[A-Za-z0-9]+$/;//字母和数字
    // 登录过期的时候,跳出ifram框架
    if (top.location !== self.location) top.location = self.location;
    //文本框回车提交
    $(".layui-input").keydown(function (e) {
        if (e.keyCode === 13) {
            $("#submitBtn").trigger("click");
        }
    });
    form.verify({
        account: function (values) {
            if (!iphone_reg.test(values)) {
                return "请使用手机号码进行登录";
            }
        },
        password: function (values) {
            if (!pass_reg.test(values)) {
                return "必须包含大小写字母和数字的组合,不能使用特殊字符,长度不小于8位";
            }
        },
        captcha: function (values) {
            if (values.length !== 5) {
                return "请输入5位长度的验证码";
            }
            if (!base_reg.test(values)) {
                return "请输入5位长度的验证码";
            }
        }
    })
    $("#captchaPic").click(function () {
        $(this).attr("src", "/api/v1/verify/getTextVerify?t=" + Math.random());
    })
    // 进行登录操作
    form.on('submit(login)', function (data) {
        var td = data.field;
        ajax.request({
            method: "/user/doTextVerifyLogin",
            type: "post",
            callback: function (res) {
                layer.msg(res.msg, {icon: res.code === 0 ? 1 : 5, time: 1000}, function () {
                    if (res.code === 0) {
                        layui.data("webapp", {
                            key: "data",
                            value: res.data
                        });
                    } else {
                        $("#captcha").val("");
                        $("#captchaPic").trigger("click");
                    }
                });
            }
        }, td);
        return false;
    });
});

4.java

@RequestMapping(value = "/getTextVerify")
public void getverify(HttpServletRequest request, HttpServletResponse response) {
    try {
        TextVerifyUtil verifyUtil = new TextVerifyUtil();
        response.setContentType("image/jpeg");
        response.setHeader("Pragma", "No-cache");
        response.setHeader("Cache-Control", "no-cache");
        response.setDateHeader("Expire", 0);
        verifyUtil.getRandomCode(request, response);//输出验证码图片方法
    } catch (Exception e) {
        e.printStackTrace();
    }
}

5.TextVerifyUtil

package com.cn.springboot.utils;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.Random;

public class TextVerifyUtil {

    public static final String RANDOMCODEKEY = "TEXT_VERIFY";//放到session中的key
    private static final Logger logger = LoggerFactory.getLogger(TextVerifyUtil.class);
    private String randString = "123456789ABCDEFGHIJKLMNPQRSTUVWXYZ";//随机产生数字与字母组合的字符串
    private int width = 120;// 图片宽
    private int height = 35;// 图片高
    private int lineSize = 40;// 干扰线数量
    private int stringNum = 5;// 随机产生字符数量
    private int fontSize=24;//字号大小
    private Random random = new Random();

    /**
     * 获得字体
     */
    public TextVerifyUtil(int width, int height, int lineSize, int stringNum){
        this.width=width;
        this.height=height;
        this.lineSize=lineSize;
        this.stringNum=stringNum;
    }

    public TextVerifyUtil(){
    }

    /**
     * 生成随机图片
     */
    public void getRandomCode(HttpServletRequest request, HttpServletResponse response) {
        HttpSession session = request.getSession();
        // BufferedImage类是具有缓冲区的Image类,Image类是用于描述图像信息的类
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_BGR);
        // 产生Image对象的Graphics对象,改对象可以在图像上进行各种绘制操作
        Graphics g = image.getGraphics();
        g.fillRect(0, 0, width, height);//图片大小
        g.setFont(new Font("Times New Roman", Font.ROMAN_BASELINE, fontSize));//字体大小
        g.setColor(getRandColor(110, 133));//字体颜色
        // 绘制干扰线
        for (int i = 0; i <= lineSize; i++) {
            drawLine(g);
        }
        // 绘制随机字符
        String randomString = "";
        for (int i = 1; i <= stringNum; i++) {
            randomString = drawString(g, randomString, i);
        }
        //将生成的随机字符串保存到session中
        session.removeAttribute(RANDOMCODEKEY);
        session.setAttribute(RANDOMCODEKEY, randomString);
        g.dispose();
        try {
            // 将内存中的图片通过流动形式输出到客户端
            ImageIO.write(image, "JPEG", response.getOutputStream());
        } catch (Exception e) {
            logger.error("将内存中的图片通过流动形式输出到客户端失败>>>>   ", e);
        }
    }

    /**
     * 获得颜色
     */
    private Color getRandColor(int fc, int bc) {
        if (fc > 255)
            fc = 255;
        if (bc > 255)
            bc = 255;
        int r = fc + random.nextInt(bc - fc - 16);
        int g = fc + random.nextInt(bc - fc - 14);
        int b = fc + random.nextInt(bc - fc - 18);
        return new Color(r, g, b);
    }

    /**
     * 绘制字符串
     */
    private String drawString(Graphics g, String randomString, int i) {
        g.setFont(getFont());
        g.setColor(new Color(random.nextInt(101), random.nextInt(111), random.nextInt(121)));
        String rand = String.valueOf(getRandomString(random.nextInt(randString.length())));
        randomString += rand;
        g.translate(random.nextInt(3), random.nextInt(3));
        g.drawString(rand, 18 * i, fontSize);
        return randomString;
    }

    private Font getFont() {
        return new Font("Fixedsys", Font.CENTER_BASELINE, fontSize);
    }

    /**
     * 绘制干扰线
     */
    private void drawLine(Graphics g) {
        int x = random.nextInt(width);
        int y = random.nextInt(height);
        int xl = random.nextInt(13);
        int yl = random.nextInt(15);
        g.drawLine(x, y, x + xl, y + yl);
    }

    /**
     * 获取随机的字符
     */
    public String getRandomString(int num) {
        return String.valueOf(randString.charAt(num));
    }

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值