zoukankan      html  css  js  c++  java
  • 学会这个工具的使用,让你快速生成验证码

    前言

    验证码是我们做人机验证最常用的方式,常用于敏感操作的验证,比如:登录、注册、修改等。

    验证码的原理:不同的客户端拥有不同的 session 对象,在看到验证码图片的时刻,服务器后端代码生成图片并将随机字符存储到 session 中。这样客户端看到的只能是图片,人工识别图片后将字符发送到服务器与 session 中的字符进行比对。

    上面只是简单的介绍了验证码的原理,更多细节还需有 javaweb 相关基础知识,这篇文章适合有基础的同学。

    最近几天我翻到了以前生成验证码的工具类,使用 Graphics2D 生成的图片,然后再以流的形式写出到客户端,这些代码还是有些问题的,都是硬编码。在以后的使用中我们可能有不同的需求都会导致代码重新修改,自定义一些样式都不是很方便。

    所以我找到了 github 上的一个生成验证码的工具:kaptcha,下面我就给大家介绍一下 kaptcha 的使用。

    kaptcha 的使用

    我们就以一个 maven 构建的 web 项目为例

    1、依赖 jar 包

    在 pom.xml 文件中添加相关依赖

    <dependency>
      <groupId>com.github.penggle</groupId>
      <artifactId>kaptcha</artifactId>
      <version>2.3.2</version>
    </dependency>
    

    2、配置生成验证码的 servlet

    修改 web.xml,添加 kaptcha 提供的 servlet 并配置映射路径

    <servlet>
        <servlet-name>Kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>Kaptcha</servlet-name>
        <url-pattern>/captcha</url-pattern>
    </servlet-mapping>
    

    访问 http://localhost:8080/captcha 这时发现就已经可以产生验证码了,但还有个问题,验证码的随机字符存在哪里了?

    3、探索 kaptcha

    我们来查看 KaptchaServlet 这个类的源码,doGet 方法

    @Override
    public void doGet(HttpServletRequest req, HttpServletResponse resp)
    		throws ServletException, IOException
    {
    	// Set to expire far in the past.
    	resp.setDateHeader("Expires", 0);
    	// Set standard HTTP/1.1 no-cache headers.
    	resp.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
    	// Set IE extended HTTP/1.1 no-cache headers (use addHeader).
    	resp.addHeader("Cache-Control", "post-check=0, pre-check=0");
    	// Set standard HTTP/1.0 no-cache header.
    	resp.setHeader("Pragma", "no-cache");
    
    	// return a jpeg
    	resp.setContentType("image/jpeg");
    
    	// create the text for the image
    	String capText = this.kaptchaProducer.createText();
    
    	// store the text in the session
    	req.getSession().setAttribute(this.sessionKeyValue, capText);
    
    	// store the date in the session so that it can be compared
    	// against to make sure someone hasn't taken too long to enter
    	// their kaptcha
    	req.getSession().setAttribute(this.sessionKeyDateValue, new Date());
    
    	// create the image with the text
    	BufferedImage bi = this.kaptchaProducer.createImage(capText);
    
    	ServletOutputStream out = resp.getOutputStream();
    
    	// write the data out
    	ImageIO.write(bi, "jpg", out);
    }
    

    有这样一段代码,获取字符后存入 session 中,键为 sessionKeyValue 这个变量的值

    // create the text for the image
    String capText = this.kaptchaProducer.createText();
    // store the text in the session
    req.getSession().setAttribute(this.sessionKeyValue, capText);
    

    sessionKeyValue 这个变量的值在 init 方法中被赋值

    this.sessionKeyValue = config.getSessionKey();
    

    好我们进入 config.getSessionKey() 中查看代码,发现 session 的键为 Constants 这个类中的常量 Constants.KAPTCHA_SESSION_KEY

    return this.properties.getProperty(Constants.KAPTCHA_SESSION_CONFIG_KEY, Constants.KAPTCHA_SESSION_KEY);
    

    4、编写测试验证码是否正常使用的 servlet

    我们来验证一下,编写一个 servlet

    import com.google.code.kaptcha.Constants;
    
    import javax.servlet.ServletException;
    import javax.servlet.annotation.WebServlet;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    import java.io.IOException;
    import java.io.PrintWriter;
    
    @WebServlet("/test")
    public class TestKaptchaServlet extends HttpServlet {
        @Override
        protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            resp.setContentType("text/html;charset=utf-8");
            PrintWriter out = resp.getWriter();
            //获取传入的验证码
            String captcha = req.getParameter("captcha");
            if (null != captcha) {
                //获取实际session中的验证码
                String code = (String) req.getSession().getAttribute(Constants.KAPTCHA_SESSION_KEY);
                if (null == code){
                    resp.sendRedirect("/captcha");
                    return;
                }
                if (code.equalsIgnoreCase(captcha)) {
                    out.print("验证输入正确");
                } else {
                    out.print("验证码输入有误");
                }
            } else {
                out.print("必须输入验证码");
            }
            out.flush();
            out.close();
        }
    
        @Override
        protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
            this.doGet(req, resp);
        }
    }
    

    先访问验证码 http://localhost:8080/captcha 然后访问 http://localhost:8080/test?captcha=验证码

    以上这些默认配置能满足一般业务的使用了,下面通过深入解析 kaptcha 的源码自定义配置验证码的宽、高、边框、颜色、字符等

    5、深入源码自定义配置 kaptcha

    再来看一下 init 方法中的代码

    @Override
    public void init(ServletConfig conf) throws ServletException
    {
    	super.init(conf);
    
    	// Switch off disk based caching.
    	ImageIO.setUseCache(false);
    
    	Enumeration<?> initParams = conf.getInitParameterNames();
    	while (initParams.hasMoreElements())
    	{
    		String key = (String) initParams.nextElement();
    		String value = conf.getInitParameter(key);
    		this.props.put(key, value);
    	}
    
    	Config config = new Config(this.props);
    	this.kaptchaProducer = config.getProducerImpl();
    	this.sessionKeyValue = config.getSessionKey();
    	this.sessionKeyDateValue = config.getSessionDate();
    }
    

    这段代码获取 servlet 的初始化参数,并将参数存入 config 对象中,看 config 中的一段代码

    public boolean isBorderDrawn()
    {
    	String paramName = Constants.KAPTCHA_BORDER;
    	String paramValue = this.properties.getProperty(paramName);
    	return this.helper.getBoolean(paramName, paramValue, true);
    }
    

    没错,所有的参数名字都是 Constants 类中常量名称

    public class Constants
    {
    	public final static String KAPTCHA_SESSION_KEY = "KAPTCHA_SESSION_KEY";
    
    	public final static String KAPTCHA_SESSION_DATE = "KAPTCHA_SESSION_DATE";
    
    	public final static String KAPTCHA_SESSION_CONFIG_KEY = "kaptcha.session.key";
    	
    	//省略其他代码
    }
    

    所以,可以给 KaptchaServlet 在 web.xml 配置参数,下面这些配置给大家参考

    <servlet>
        <servlet-name>Kaptcha</servlet-name>
        <servlet-class>com.google.code.kaptcha.servlet.KaptchaServlet</servlet-class>
    
        <!-- 是否有边框 -->
        <init-param>
            <param-name>kaptcha.border</param-name>
            <param-value>no</param-value>
        </init-param>
        <!-- 字体颜色 -->
        <init-param>
            <param-name>kaptcha.textproducer.font.color</param-name>
            <param-value>red</param-value>
        </init-param>
        <!-- 图片宽度 -->
        <init-param>
            <param-name>kaptcha.image.width</param-name>
            <param-value>135</param-value>
        </init-param>
        <!-- 使用哪些字符生成验证码 -->
        <init-param>
            <param-name>kaptcha.textproducer.char.string</param-name>
            <param-value>ACDEFHKPRSTWX345679</param-value>
        </init-param>
        <!-- 图片高度 -->
        <init-param>
            <param-name>kaptcha.image.height</param-name>
            <param-value>50</param-value>
        </init-param>
        <!-- 字体大小 -->
        <init-param>
            <param-name>kaptcha.textproducer.font.size</param-name>
            <param-value>38</param-value>
        </init-param>
        <!-- 干扰线的颜色 -->
        <init-param>
            <param-name>kaptcha.noise.color</param-name>
            <param-value>black</param-value>
        </init-param>
        <!-- 字符个数 -->
        <init-param>
            <param-name>kaptcha.textproducer.char.length</param-name>
            <param-value>6</param-value>
        </init-param>
        <!-- 使用哪些字体 -->
        <init-param>
            <param-name>kaptcha.textproducer.font.names</param-name>
            <param-value>Arial</param-value>
        </init-param>
    </servlet>
    
    <servlet-mapping>
        <servlet-name>Kaptcha</servlet-name>
        <url-pattern>/captcha</url-pattern>
    </servlet-mapping>
    
  • 相关阅读:
    SSIS 学习之旅 FTP文件传输-脚本任务
    SSIS 学习之旅 FTP文件传输-FTP任务
    SSIS 学习之旅 数据同步
    SSIS 学习之旅 第一个SSIS 示例(二)
    SSIS 学习之旅 第一个SSIS 示例(一)(下)
    SSIS 学习之旅 第一个SSIS 示例(一)(上)
    图解 VS2015 如何打包winform 安装程序
    常用SQL Server 语句
    蓝桥杯 算法训练 Remember the A La Mode
    Competition in Swiss-system——2019CCPC哈尔滨 C题
  • 原文地址:https://www.cnblogs.com/AIThink/p/10476492.html
Copyright © 2011-2022 走看看