验证码生成之Jcaptcha
今天看了下之前项目的验证码生成逻辑,发现使用的是Jcaptcha,很好奇验证码生成后是存储在哪里的,所以Debug研究了下源码,从头说吧。
一、验证码的生成及存储
1.页面如何展示验证码的
在这里插入图片描述
页面通过请求/pub/jcaptcha.servlet地址,生成验证码,找了下这个地址,发现是最简单的servlet请求,配置在了web.xml中,如下所示:
在这里插入图片描述
随即进入对应的类ImageCaptchaServlet
2.验证码逻辑处理类ImageCaptchaServlet
在这里插入图片描述
如上图所示,这个类中最重要的两个方法是doGet()和validateResponse();
doGet():对应页面请求/pub/jcaptcha.servlet,用于生成验证码
validateResponse():用于校验验证码是否输入正确
3.Debug跟踪doGet()(拣最重要的逻辑来说)
在这里插入图片描述
这个方法中,参数id为SessionID,locale为"zh_CN",times为一个HashMap,存放了以SessionID为key,当前时间为value的键值对,接着通过调用generateAndStoreCaptcha()方法生成验证码,进入该方法

在这里插入图片描述
从Debug变量中可以看出,已"zh_CN"为入参,调用getNextCaptcha()生成了四位数字加字母的验证码,随后调用storeCaptcha()将验证码保存到了store中并返回验证码,进入保存验证码的方法
在这里插入图片描述
以SessionID为key,验证码为value,存储到了store中,并且store的size加1,我们看下store是个啥,
在这里插入图片描述
store就是一个HashMap集合,由此我们可以得出,使用Jcaptcha生成的验证码,是保存到了map集合中,并且它的key为当前的SessionID.
二、验证码的校验
从验证码的生成去推测验证码的校验:验证码生成后存到了map集合中,去map集合中查看值是否存在并且是否相等,无非就是通过key从map中拿到value,与页面输入的验证码进行比较,咱们看下是不是这个逻辑。
在这里插入图片描述
ID同样为当前的SessionID,先判断store集合中是否有这个key,没有的话抛出异常;有的话,则使用store.getCaptcha(ID)拿到key对应的value,再通过value.validateResponse(response)验证与页面输入的验证码是否相同,进入验证方法
在这里插入图片描述
返回验证的结果true或者是false在这里插入图片描述
看this.store.removeCaptcha(ID)这行代码,无论验证结果是正确还是失败,都要从map中将该键值对移除,我们可以看到store集合的大小也减1了
在这里插入图片描述
同时times集合中对应的键值对也移除了,times集合的作用不知道是啥?只是知道times和store两个集合的数据是一同生成,一同删除的。

结论:使用Jcaptcha生成的验证码,以当前session的SessionID为key,以四位数的验证码为value,存到了HashMap集合中,验证验证码是否输入正确时,再以当前session的SessionID去集合中取到对应的value,与页面输入的验证码比较。

在测试的时候发现这么一个问题:单机模式下,map集合保存在内存中,因为集合中的键值对只有要验证后才会被移除,那么当生成验证码后,我关闭了浏览器,当前会话结束,SessionID丢失,那么集合中对应的键值对就不会被验证,这条数据就会变成垃圾数据,除非服务器重启,否则该数据一直存在,首先就造成了内存的浪费

如果把验证码的键值对保存在redis中,验证码加上有效期,那么即便出现以上这种情况,在超过有效期后,验证码会自动删除,不会造成内存的浪费,这种方案待实践,看下新的项目中是怎么处理的?

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐