Spring Boot中验证码实现kaptcha

要生成验证码网上的方案比较多,基本是基于两大类:1为自定义生成,操作用Image类,2为kaptcha生成,有模糊算法。

当然也可以直接交由前端进行处理

1、基于kaptcha

首先不要怀疑的是报名是GitHub还是Google的,因为都是出自私人的产物,并且之前在Google Code进行托管,然后关闭了Google Code之后,有人就把其转入到GitHub中,并且不只一个人,所以才会造成市面上这么多不同的报名。

但总体功能基本不变。

下面POM先引入包:

<!-- https://mvnrepository.com/artifact/com.github.penggle/kaptcha -->
<dependency>
    <groupId>com.github.penggle</groupId>
    <artifactId>kaptcha</artifactId>
    <version>2.3.2</version>
</dependency>

这个包也不要怀疑,在GitHub上的星星是最多的。

KaptchaConfig.java

import java.util.Properties;  
  
import org.springframework.context.annotation.Bean;  
import org.springframework.stereotype.Component;  
  
import com.google.code.kaptcha.impl.DefaultKaptcha;  
import com.google.code.kaptcha.util.Config;  
  
@Component  
public class KaptchaConfig {  
    @Bean  
    public DefaultKaptcha getDefaultKaptcha(){  
        com.google.code.kaptcha.impl.DefaultKaptcha defaultKaptcha = new com.google.code.kaptcha.impl.DefaultKaptcha();  
        Properties properties = new Properties();  
        properties.setProperty("kaptcha.border", "yes");  
        properties.setProperty("kaptcha.border.color", "105,179,90");  
        properties.setProperty("kaptcha.textproducer.font.color", "blue");  
        properties.setProperty("kaptcha.image.width", "110");  
        properties.setProperty("kaptcha.image.height", "40");  
        properties.setProperty("kaptcha.textproducer.font.size", "30");  
        properties.setProperty("kaptcha.session.key", "code");  
        properties.setProperty("kaptcha.textproducer.char.length", "4");  
        properties.setProperty("kaptcha.textproducer.font.names", "宋体,楷体,微软雅黑");  
        Config config = new Config(properties);  
        defaultKaptcha.setConfig(config);  
          
        return defaultKaptcha;  
    }  
}  

这个配置文件可以写成XML,然后通过在main方法使用@ImportResource进行导入XML配置:

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans"  
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">  
    <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">  
                    <props>  
                        <prop key = "kaptcha.border ">yes</prop>  
                            <prop key="kaptcha.border.color">105,179,90</prop>  
                            <prop key="kaptcha.textproducer.font.color">blue</prop>  
                            <prop key="kaptcha.image.width">100</prop>  
                            <prop key="kaptcha.image.height">50</prop>  
                            <prop key="kaptcha.textproducer.font.size">27</prop>  
                            <prop key="kaptcha.session.key">code</prop>  
                            <prop key="kaptcha.textproducer.char.length">4</prop>  
                            <prop key="kaptcha.textproducer.font.names">宋体,楷体,微软雅黑</prop>  
                            <prop key="kaptcha.textproducer.char.string">0123456789ABCEFGHIJKLMNOPQRSTUVWXYZ</prop>  
                            <prop key="kaptcha.obscurificator.impl">com.google.code.kaptcha.impl.WaterRipple</prop>  
                            <prop key="kaptcha.noise.color">black</prop>  
                            <prop key="kaptcha.noise.impl">com.google.code.kaptcha.impl.DefaultNoise</prop>  
                            <prop key="kaptcha.background.clear.from">185,56,213</prop>  
                            <prop key="kaptcha.background.clear.to">white</prop>  
                            <prop key="kaptcha.textproducer.char.space">3</prop>  
                    </props>  
                </constructor-arg>  
            </bean>  
        </property>  
    </bean>  
  
</beans>  
@SpringBootApplication  
@ImportResource(locations={"classpath:mykaptcha.xml"})  
public class Application {  
  
    public static void main(String[] args) {  
        SpringApplication.run(Application.class, args);  
    }  
}  

注意:以上的main方法是导入XML文件的写法,普通注解方式不需要这么写。普通即可。

Controller,生成验证码

@Autowired  
DefaultKaptcha defaultKaptcha;

@RequestMapping("/defaultKaptcha")  
public void defaultKaptcha(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse) throws Exception{  
            byte[] captchaChallengeAsJpeg = null;    
             ByteArrayOutputStream jpegOutputStream = new ByteArrayOutputStream();    
             try {    
             //生产验证码字符串并保存到session中  
             String createText = defaultKaptcha.createText();  
             httpServletRequest.getSession().setAttribute("vrifyCode", createText);  
             //使用生产的验证码字符串返回一个BufferedImage对象并转为byte写入到byte数组中  
             BufferedImage challenge = defaultKaptcha.createImage(createText);  
             ImageIO.write(challenge, "jpg", jpegOutputStream);  
             } catch (IllegalArgumentException e) {    
                 httpServletResponse.sendError(HttpServletResponse.SC_NOT_FOUND);    
                 return;    
             }   
         
             //定义response输出类型为image/jpeg类型,使用response输出流输出图片的byte数组  
             captchaChallengeAsJpeg = jpegOutputStream.toByteArray();    
             httpServletResponse.setHeader("Cache-Control", "no-store");    
             httpServletResponse.setHeader("Pragma", "no-cache");    
             httpServletResponse.setDateHeader("Expires", 0);    
             httpServletResponse.setContentType("image/jpeg");    
             ServletOutputStream responseOutputStream =    
                     httpServletResponse.getOutputStream();    
             responseOutputStream.write(captchaChallengeAsJpeg);    
             responseOutputStream.flush();    
             responseOutputStream.close();    
}  

验证方法

@RequestMapping("/imgvrifyControllerDefaultKaptcha")  
public ModelAndView imgvrifyControllerDefaultKaptcha(HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){  
    ModelAndView andView = new ModelAndView();  
     String captchaId = (String) httpServletRequest.getSession().getAttribute("vrifyCode");    
     String parameter = httpServletRequest.getParameter("vrifyCode");  
     System.out.println("Session  vrifyCode "+captchaId+" form vrifyCode "+parameter);  
       
    if (!captchaId.equals(parameter)) {  
        andView.addObject("info", "错误的验证码");  
        andView.setViewName("index");  
    } else {  
        andView.addObject("info", "登录成功");  
        andView.setViewName("succeed");  
          
    }  
    return andView;  
}  

配置项参考:

kaptcha.border  是否有边框  默认为true  我们可以自己设置yes,no  
kaptcha.border.color   边框颜色   默认为Color.BLACK  
kaptcha.border.thickness  边框粗细度  默认为1  
kaptcha.producer.impl   验证码生成器  默认为DefaultKaptcha  
kaptcha.textproducer.impl   验证码文本生成器  默认为DefaultTextCreator  
kaptcha.textproducer.char.string   验证码文本字符内容范围  默认为abcde2345678gfynmnpwx  
kaptcha.textproducer.char.length   验证码文本字符长度  默认为5  
kaptcha.textproducer.font.names    验证码文本字体样式  默认为new Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)  
kaptcha.textproducer.font.size   验证码文本字符大小  默认为40  
kaptcha.textproducer.font.color  验证码文本字符颜色  默认为Color.BLACK  
kaptcha.textproducer.char.space  验证码文本字符间距  默认为2  
kaptcha.noise.impl    验证码噪点生成对象  默认为DefaultNoise  
kaptcha.noise.color   验证码噪点颜色   默认为Color.BLACK  
kaptcha.obscurificator.impl   验证码样式引擎  默认为WaterRipple  
kaptcha.word.impl   验证码文本字符渲染   默认为DefaultWordRenderer  
kaptcha.background.impl   验证码背景生成器   默认为DefaultBackground  
kaptcha.background.clear.from   验证码背景颜色渐进   默认为Color.LIGHT_GRAY  
kaptcha.background.clear.to   验证码背景颜色渐进   默认为Color.WHITE  
kaptcha.image.width   验证码图片宽度  默认为200  
kaptcha.image.height  验证码图片高度  默认为50

2、自定义方案

验证码生成类

import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.OutputStream;import java.util.HashMap;
import java.util.Map;import java.util.Random;

public class ImageCode {
    private static char mapTable[] = {
            '0', '1', '2', '3', '4', '5',
            '6', '7', '8', '9', '0', '1',
            '2', '3', '4', '5', '6', '7',
            '8', '9'};
    public static Map<String, Object> getImageCode(int width, int height, OutputStream os) {
        Map<String,Object> returnMap = new HashMap<String, Object>();
        if (width <= 0) width = 60;
        if (height <= 0) height = 20;
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // 获取图形上下文
        Graphics g = image.getGraphics();
        //生成随机类
        Random random = new Random();
        // 设定背景色
        g.setColor(getRandColor(200, 250));
        g.fillRect(0, 0, width, height);
        //设定字体
        g.setFont(new Font("Times New Roman", Font.PLAIN, 18));
        // 随机产生168条干扰线,使图象中的认证码不易被其它程序探测到
        g.setColor(getRandColor(160, 200));
        for (int i = 0; i < 168; i++) {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            g.drawLine(x, y, x + xl, y + yl);
        }
        //取随机产生的码
        String strEnsure = "";
        //4代表4位验证码,如果要生成更多位的认证码,则加大数值
        for (int i = 0; i < 4; ++i) {
            strEnsure += mapTable[(int) (mapTable.length * Math.random())];
            // 将认证码显示到图象中
            g.setColor(new Color(20 + random.nextInt(110), 20 + random.nextInt(110), 20 + random.nextInt(110)));
            //直接生成
            String str = strEnsure.substring(i, i + 1);
            g.drawString(str, 13 * i + 6, 16);
        }
        // 释放图形上下文
        g.dispose();
        returnMap.put("image",image);
        returnMap.put("strEnsure",strEnsure);
        return returnMap;
    }
    //给定范围获得随机颜色
    static Color getRandColor(int fc, int bc) {
        Random random = new Random();
        if (fc > 255) fc = 255;
        if (bc > 255) bc = 255;
        int r = fc + random.nextInt(bc - fc);
        int g = fc + random.nextInt(bc - fc);
        int b = fc + random.nextInt(bc - fc);
        return new Color(r, g, b);
    }
}

获取验证码API

@RequestMapping(value = "/images/imagecode")
public String imagecode(HttpServletRequest request, HttpServletResponse response) throws Exception {
    OutputStream os = response.getOutputStream();
    Map<String,Object> map = ImageCode.getImageCode(60, 20, os);
    String simpleCaptcha = "simpleCaptcha";
    request.getSession().setAttribute(simpleCaptcha, map.get("strEnsure").toString().toLowerCase());
    request.getSession().setAttribute("codeTime",new Date().getTime());
    try {
        ImageIO.write((BufferedImage) map.get("image"), "JPEG", os);
    } catch (IOException e) {
        return "";
    }
    return null;
}

验证验证码API

@RequestMapping(value = "/checkcode")
@ResponseBody
public String checkcode(HttpServletRequest request, HttpSession session) throws Exception {
    String checkCode = request.getParameter("checkCode");
    Object cko = session.getAttribute("simpleCaptcha") ; //验证码对象
    if(cko == null){
        request.setAttribute("errorMsg", "验证码已失效,请重新输入!");
        return "验证码已失效,请重新输入!";
    }
    String captcha = cko.toString();
    Date now = new Date();
    Long codeTime = Long.valueOf(session.getAttribute("codeTime")+"");
    if(StringUtils.isEmpty(checkCode) || captcha == null ||  !(checkCode.equalsIgnoreCase(captcha))) {
        request.setAttribute("errorMsg", "验证码错误!");
        return "验证码错误!";
    } else if ((now.getTime()-codeTime)/1000/60>5) {
        //验证码有效时长为5分钟
        request.setAttribute("errorMsg", "验证码已失效,请重新输入!");
        return "验证码已失效,请重新输入!";
    }else {
        session.removeAttribute("simpleCaptcha");
        return "1";
    }
}

 

 

参考:

http://blog.csdn.net/u014104286/article/details/70515004

http://blog.csdn.net/liunian02050328/article/details/53462053

http://www.jb51.net/article/115800.htm

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

http://www.jianshu.com/p/7a37077a41e4

http://www.voidcn.com/article/p-ewnhqlod-bmc.html

posted @ 2017-10-24 00:43  EasonJim  阅读(2493)  评论(0编辑  收藏  举报