Java Web项目使用图形验证码 — Kaptcha

一、验证码介绍

生成的主要方式:

1.使用Java原生的方式,其中包含了Servlet、AWT、ImageIO的使用;

2.使用开源库,例如Jcaptcha、Kaptcha...;

    (各图形验证码开源库:http://www.oschina.net/project/tag/248/captcha?lang=19

另外,生成code可以保存在Session或Cookie,也可以保存在缓存(例如,Redis);

需要验证的时候,需要把从Session或者缓存中取出并与请求的验证码进行校验;

二、项目中使用验证码

项目中使用的是Google的开源库 - Kaptcha;注意:本项目使用了Spring MVC;

1.引入Maven

<dependency>
    <groupId>com.google.code</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

2.Spring配置Bean

更多Kaptcha配置请移步底部资料;

    <!--图形验证码-->
    <bean id="captchaProducer" class="com.google.code.kaptcha.impl.DefaultKaptcha">
        <property name="config">
            <bean class="com.google.code.kaptcha.util.Config">
                <constructor-arg type="java.util.Properties">
                    <value>
                        kaptcha.border=yes
                    </value>
                </constructor-arg>
            </bean>
        </property>
    </bean>

3.Controller中代码实现

@RestController
@RequestMapping(value = "/verify", name = "图片验证码")
public class ValidateCoderController {

    private Logger logger = LoggerFactory.getLogger(ValidateCoderController.class);

    @Autowired
    private Producer captchaProducer;

    @RequestMapping(value = "/code", method = RequestMethod.GET, name = "图片验证码")
    public void code(HttpServletResponse response,
                     @RequestParam(value = "mobilePhone", required = true) String mobilePhone,
                     @RequestParam(value = "captchaType", required = true) Integer captchaType) {
        if (!StrUtils.isPhoneNumber(mobilePhone)) {
            return;
        }
        CaptchaType type = getCaptchaTypeByCode(captchaType);
        if (isTooOften(mobilePhone, type.getValue())) {
            logger.info("号码{}获取{}图片验证码频繁", mobilePhone, type.getBundleKey());
            return;
        }

        response.setDateHeader("Expires", 0);
        response.setHeader("Cache-Control", "no-store, no-cache, must-revalidate");
        response.addHeader("Cache-Control", "post-check=0, pre-check=0");
        response.setHeader("Pragma", "no-cache");
        response.setContentType("image/jpeg");
        try (ServletOutputStream out = response.getOutputStream()) {
            String capText = captchaProducer.createText().substring(0, 4);
            BufferedImage bi = captchaProducer.createImage(capText);
            ImageIO.write(bi, "jpg", out);
            //设置验证码
            RedisConnector.save(mobilePhone, capText, type.getValue());
            
            /*移动端需要base64处理后返回,然后response的Headers不用配置;
              此处需要使用ByteArrayOutputStream
            BASE64Encoder encoder = new BASE64Encoder();
            String base64String = encoder.encode(out.toByteArray());
            */
        } catch (IOException e) {
            e.printStackTrace();
            logger.error("号码{}获取{}图片验证码失败", mobilePhone, type.getBundleKey());
        }
    }

    private boolean isTooOften(String mobilePhone, String loginPre) {
        String key = KeyUtils.getLimitKey(mobilePhone, loginPre);
        if (RedisConnector.exists(key)) {
            String countStr = RedisConnector.getData(key);
            int count = Integer.parseInt(countStr);
            if (count >= 30) {
                return true;
            }
        }
        return false;
    }
}

4.验证码校验

需要使用的地方从Redis取出校验,这里需要注意的是:

    1)Redis的Keys的生成工具类KeysUtils;

    2)操作Redis的工具,以及Code的有效时间;

    3)校验验证码成功需要使其失效;

Java原生方式:

http://tedhacker.top/2016/11/07/Java%E7%94%9F%E6%88%90%E9%AA%8C%E8%AF%81%E7%A0%81%E7%AE%80%E8%AE%B0/

https://www.jianshu.com/p/05409731abb8

使用Kaptcha:

https://www.jianshu.com/p/3a695783c5c1

http://blog.csdn.net/rambo_china/article/details/7720181

猜你喜欢

转载自my.oschina.net/itommy/blog/1630497