起因还是因为腾飞学给我下发的任务,让我把eladmin的持久层框架jpa换成我们熟悉的mybatis/mybatis plus,这可谓是一个比较庞大的工程,因为要保证eladmin前端在接口不变的情况下可以直接登录使用,这就要求你要掌握整个eladmin源码的运行流程。
就在第二天转化security模块中的获取验证码接口时,发现了一个比较奇怪的情况,当输入验证码结果为0的情况时,提示输入验证码错误,例如:0+0、0x9等。起初我以为我只是自己看错了,也没在意,其他的验证码结果可以通过是正确的,但是之后却发现确实在结果为0的时候提示了验证码输入错误,而其他结果输入就显示正确。
第一时间先是和小桑学长提出这个问题,经排查后发现redis里存入的验证码结果是“0.0”,是一个浮点型数据,难怪前端输入0会报错,我刷新了几次验证码又找到一个结果为0的验证码,这次输入0.0就成功了,看来是验证码放入redis的问题,那就是在获取验证码接口中出了问题。
eladmin引入的验证码为:
<dependency>
<groupId>com.github.whvcse</groupId>
<artifactId>easy-captcha</artifactId>
<version>1.6.2</version>
</dependency>
最新的版本1.6.2也是1年前的了。eladmin中获取验证码的接口是在security模块下的rest/AuthorizationController中的/code接口。eladmin默认使用的是算数型验证码,放入缓存中的值为captcha.text(),Captcha是验证码类,text()方法是将验证码的结果以字符形式输出,那问题就出现在这里了,经测试,当验证码类型为 arithmetic时且长度 >= 2 时,captcha.text()的结果有几率为浮点型,那么根本的问题其实不在于eladmin,而是easy-captcha的问题,不过可以先治标,解决方法就是对captcha.text()的结果以"."分割,取第一部分,这样就可以把数据的小数部分去掉,鲁棒性也比较高。
String captchaValue = captcha.text();
if (captcha.getCharType() - 1 == LoginCodeEnum.arithmetic.ordinal() & captchaValue.contains(".")) {
captchaValue = captchaValue.split("\\.")[0];
}
修改之后便给github eladmin提了一个pr,等待着管理员elunez的审核通过,毕竟这是第一次给人家大的开源项目提pr,还是比较紧张的。
学长鼓励我追寻根本原因,之后又把easy-captcha的源码给拉了下来,经一段时间的排查定位到根本问题是在算数型验证码抽象类中的问题,在ArithmeticCaptchaAbstract中一串代码:
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("javascript");
try {
chars = String.valueOf(engine.eval(sb.toString().replaceAll("x", "*")));
} catch (ScriptException e) {
e.printStackTrace();
}
其中关键问题就是在engine.eval中,这个方法可以计算出一个算数式的结果并输出,但是返回值类型Object,而实际有一部分为整形,一部分为浮点型,而easy-captcha并未对其处理,而是直接转成字符串,而text()方法输出的就是这个。由于强转也比较麻烦,最后也是用了比较粗暴的办法就是直接分割字符串——split("\.")[0];
顺便也提了一个pr,但是这个可能审批过的概率不大,毕竟上次更新都是7个月之前的事了。而我给eladmin提的pr也是一天天过去,其中有看到比我提交的早的分支被关闭,我还是比较恐慌的。
之后小桑学长在测试部门的时候又发现了一个bug,但是eladmin官方在几天前最新的一次分支就是这个bug的修复,但是小桑学长说可以简化写法,我就根据小桑学长的写法又提了个pr,不料这次过了一会就被关闭了,并不是没被采纳,而是eladmin自己根据小桑学长的的方法改了代码。
这个关了就关了吧,还剩一个pr。终于,9天过后,我的邮箱收到了一封邮件,显示 Merged #464 into master. 功夫不负有心人,提的pr总算是合进去了。
最后还要感谢小桑学长的帮助。