> 文章列表 > Java实现图片验证码功能

Java实现图片验证码功能

Java实现图片验证码功能

文章目录

  • 一、背景
  • 二、实现步骤
    • 1、maven中加入依赖
    • 2、CaptchaController.java
    • 3、生成验证码配置
    • 4、CaptchaService.java接口
    • 5、CaptchaServiceImpl.java实现类
    • 6、增加验证码校验
    • 涉及文件

一、背景

在实现登录功能时,为了防止特定的程序暴力破解,一般为了安全都会在用户登录时增加otp动态验证码录。otp验证码 otp全称叫One-time Password,也称动态口令,是指计算机系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或很短。

常见验证码分为图片验证码和短信验证码,还有滑动窗口模块和选中指定物体验证方式。下面通过Java来实现图片验证码示例,效果如下:

Java实现图片验证码功能

二、实现步骤

1、maven中加入依赖

pom.xml引入依赖:

<dependency><groupId>com.github.penggle</groupId><artifactId>kaptcha</artifactId><version>2.3.2</version>
</dependency>
<dependency><groupId>com.github.whvcse</groupId><artifactId>easy-captcha</artifactId><version>1.6.2</version>
</dependency>

2、CaptchaController.java

 /*** 验证码*/@GetMapping("/captcha/digit")@ApiOperation(value = "获取数字验证码", notes = "获取数字验证码", tags = "验证码相关")@ApiImplicitParams({@ApiImplicitParam(name = "uuid", value = "uuid", required = true, paramType = "query")})@PassTokenpublic void captcha(HttpServletResponse response, String uuid) throws IOException {response.setHeader("Cache-Control", "no-store, no-cache");response.setContentType("image/jpeg");log.info("获取验证码,uuid:{}", uuid);//获取图片验证码BufferedImage image = captchaService.getCaptcha(uuid);log.info("获取验证码,uuid:{},return:{}", uuid, JSON.toJSONString(image));ServletOutputStream out = response.getOutputStream();ImageIO.write(image, "jpg", out);IOUtils.closeQuietly(out);}@GetMapping("/captcha/graphics")@ApiOperation(value = "获取图形验证码", notes = "获取图形验证码", tags = "验证码相关")@ApiImplicitParams({@ApiImplicitParam(name = "uuid", value = "uuid", required = true, paramType = "query"),@ApiImplicitParam(name = "type", value = "类型 png:png gif:gif cn:中文 cngif:中文gif arithmeti:算术", required = false, paramType = "query")})public void captcha(HttpServletRequest request, HttpServletResponse response,@RequestParam String uuid,@RequestParam(defaultValue = "arithmeti", required = false) String type) throws Exception {// 设置请求头为输出图片类型response.setContentType("image/gif");response.setHeader("Pragma", "No-cache");response.setHeader("Cache-Control", "no-cache");response.setDateHeader("Expires", 0);Captcha captcha = null;switch (type) {case "png":captcha = new SpecCaptcha(130, 48);break;case "gif":// gif类型captcha = new GifCaptcha(130, 48);break;case "cn":// 中文类型captcha = new ChineseCaptcha(130, 48, 5, new Font("楷体", Font.PLAIN, 28));break;case "cngif":// 中文gif类型captcha = new ChineseGifCaptcha(130, 48, 5, new Font("楷体", Font.PLAIN, 28));break;case "arithmeti":// 算术类型ArithmeticCaptcha arithmeticCaptcha = new ArithmeticCaptcha(130, 48);arithmeticCaptcha.setLen(3);  // 几位数运算,默认是两位arithmeticCaptcha.getArithmeticString();  // 获取运算的公式:3+2=?arithmeticCaptcha.text();  // 获取运算的结果:5captcha = arithmeticCaptcha;break;default:new SpecCaptcha(130, 48);break;}log.info("验证码:{}", captcha.text());// 设置字体
//        captcha.setFont(new Font("Verdana", Font.PLAIN, 32));  // 有默认字体,可以不用设置// 设置类型,纯数字、纯字母、字母数字混合captcha.setCharType(Captcha.TYPE_DEFAULT);//缓存验证码redisService.set(AuthKeys.AUTH_CAPTCHA, uuid, captcha.text().toLowerCase());// 输出图片流captcha.out(response.getOutputStream());}
}

3、生成验证码配置

/*** 生成验证码配置**/
@Configuration
public class KaptchaConfig {@Beanpublic DefaultKaptcha producer() {Properties properties = new Properties();//图片边框properties.setProperty("kaptcha.border", "no");//文本集合,验证码值从此集合中获取properties.setProperty("kaptcha.textproducer.char.string", "ABCDEGHJKLMNRSTUWXY23456789");//字体颜色properties.setProperty("kaptcha.textproducer.font.color", "0,84,144");//干扰颜色properties.setProperty("kaptcha.noise.color", "0,84,144");//字体大小properties.setProperty("kaptcha.textproducer.font.size", "30");//背景颜色渐变,开始颜色properties.setProperty("kaptcha.background.clear.from", "247,255,234");//背景颜色渐变,结束颜色properties.setProperty("kaptcha.background.clear.to", "247,255,234");//图片宽properties.setProperty("kaptcha.image.width", "125");//图片高properties.setProperty("kaptcha.image.height", "35");properties.setProperty("kaptcha.session.key", "code");//验证码长度properties.setProperty("kaptcha.textproducer.char.length", "4");//字体properties.setProperty("kaptcha.textproducer.font.names", "Arial,Courier,cmr10,宋体,楷体,微软雅黑");properties.put("kaptcha.textproducer.char.space", "5");Config config = new Config(properties);DefaultKaptcha defaultKaptcha = new DefaultKaptcha();defaultKaptcha.setConfig(config);return defaultKaptcha;}
}

4、CaptchaService.java接口

public interface CaptchaService {boolean validate(String uuid, String code);BufferedImage getCaptcha(String uuid);
}

5、CaptchaServiceImpl.java实现类


@Service
@Slf4j
public class CaptchaServiceImpl implements CaptchaService {@Autowiredprivate Producer producer;@Autowiredprivate RedisService redisService;@Value("${default-captcha}")private String defaultCaptcha;/*** 生成并缓存验证码,返给前端图片*/@Overridepublic BufferedImage getCaptcha(String uuid) {if (StringUtils.isEmpty(uuid)) {throw new GlobalException(BasicCodeMsg.PARAMETER_ERROR.setMsg("uuid不能为空"));}//生成文字验证码String code = producer.createText();log.info("uuid:{},验证码:{}",uuid,code);//缓存验证码redisService.set(AuthKeys.AUTH_CAPTCHA, uuid, code);return producer.createImage(code);}
}/*** 校验验证码*/@Overridepublic boolean validate(String uuid, String code) {//测试环境123456通过验证(可不加)if (EnvEnum.dev.name().equals(env) && code.equals(defaultCaptcha)) {return true;}String cacheCode = redisService.get(AuthKeys.AUTH_CAPTCHA, uuid, String.class);if (StringUtils.isEmpty(cacheCode)) {return false;}//删除缓存验证码redisService.delete(AuthKeys.AUTH_CAPTCHA, uuid);if (cacheCode.equalsIgnoreCase(code)) {return true;}return false;}

6、增加验证码校验

在登录授权验证的地方添加验证码相关校验,也就是原来校验用户名密码的地方增加。

if ("captcha".equals(type)) {LoginVo loginVo = LoginVo.builder().captcha(captcha).loginName(username).uuid(uuid).build();boolean result = captchaService.validate(uuid, captcha);if (!result) {throw new OAuth2Exception("验证码不正确");}return;

涉及文件

Java实现图片验证码功能