文章目录
一、背景
在实现登录功能时,为了防止特定的程序暴力破解,一般为了安全都会在用户登录时增加otp动态验证码录。otp验证码 otp全称叫One-time Password,也称动态口令,是指计算机系统或其他数字设备上只能使用一次的密码,有效期为只有一次登录会话或很短。
常见验证码分为图片验证码和短信验证码,还有滑动窗口模块和选中指定物体验证方式。下面通过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")})@PassTokenpublicvoidcaptcha(HttpServletResponse response,String uuid)throwsIOException{
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")})publicvoidcaptcha(HttpServletRequest request,HttpServletResponse response,@RequestParamString uuid,@RequestParam(defaultValue ="arithmeti", required =false)String type)throwsException{// 设置请求头为输出图片类型
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 =newSpecCaptcha(130,48);break;case"gif":// gif类型
captcha =newGifCaptcha(130,48);break;case"cn":// 中文类型
captcha =newChineseCaptcha(130,48,5,newFont("楷体",Font.PLAIN,28));break;case"cngif":// 中文gif类型
captcha =newChineseGifCaptcha(130,48,5,newFont("楷体",Font.PLAIN,28));break;case"arithmeti":// 算术类型ArithmeticCaptcha arithmeticCaptcha =newArithmeticCaptcha(130,48);
arithmeticCaptcha.setLen(3);// 几位数运算,默认是两位
arithmeticCaptcha.getArithmeticString();// 获取运算的公式:3+2=?
arithmeticCaptcha.text();// 获取运算的结果:5
captcha = arithmeticCaptcha;break;default:newSpecCaptcha(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、生成验证码配置
/**
* 生成验证码配置
*
*/@ConfigurationpublicclassKaptchaConfig{@BeanpublicDefaultKaptchaproducer(){Properties properties =newProperties();//图片边框
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 =newConfig(properties);DefaultKaptcha defaultKaptcha =newDefaultKaptcha();
defaultKaptcha.setConfig(config);return defaultKaptcha;}}
4、CaptchaService.java接口
publicinterfaceCaptchaService{booleanvalidate(String uuid,String code);BufferedImagegetCaptcha(String uuid);}
5、CaptchaServiceImpl.java实现类
@Service@Slf4jpublicclassCaptchaServiceImplimplementsCaptchaService{@AutowiredprivateProducer producer;@AutowiredprivateRedisService redisService;@Value("${default-captcha}")privateString defaultCaptcha;/**
* 生成并缓存验证码,返给前端图片
*/@OverridepublicBufferedImagegetCaptcha(String uuid){if(StringUtils.isEmpty(uuid)){thrownewGlobalException(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);}}/**
* 校验验证码
*/@Overridepublicbooleanvalidate(String uuid,String code){//测试环境123456通过验证(可不加)if(EnvEnum.dev.name().equals(env)&& code.equals(defaultCaptcha)){returntrue;}String cacheCode = redisService.get(AuthKeys.AUTH_CAPTCHA, uuid,String.class);if(StringUtils.isEmpty(cacheCode)){returnfalse;}//删除缓存验证码
redisService.delete(AuthKeys.AUTH_CAPTCHA, uuid);if(cacheCode.equalsIgnoreCase(code)){returntrue;}returnfalse;}
6、增加验证码校验
在登录授权验证的地方添加验证码相关校验,也就是原来校验用户名密码的地方增加。
if("captcha".equals(type)){LoginVo loginVo =LoginVo.builder().captcha(captcha).loginName(username).uuid(uuid).build();boolean result = captchaService.validate(uuid, captcha);if(!result){thrownewOAuth2Exception("验证码不正确");}return;
涉及文件
版权归原作者 一只IT攻城狮 所有, 如有侵权,请联系我们删除。