下雨的夜,总会回忆起过往的伤。
这是三天前遇见的问题,趁着还记得赶紧记下来,果然不能偷懒,攒下太长的列表就写不上了。
起源
这个内容的起源是同事找我帮忙调bug,一共调了几个小时,前面的时间没有定位到关键部分。
bug的表象是:登录时输入错误的账户,页面刷新后没有提示信息。
最后确认是多 realm 处理的逻辑与单 realm 不同,导致提示信息的代码没有处理这种特殊的异常。
就是这个配置同事直接捕获了这种异常,然后提示用户账户或密码错误。这是有问题的,如果有另一种错误出现,提示信息就不再准确。而且这是对 shiro 的错误运用,仅限于快速解决问题。
为了留下一个脚印,我决定研究出原因,给出合理的修复方案。
分析
先看看 securityManager 的配置信息,realms 里面配置了两个 realm, 这就是bug的根源。
就是这个配置翻到代码逻辑,这个 doAuthenticate 就是 shiro 用来判断处理逻辑的地方,如果只有一个 realm 就走 doSingleRealmAuthentication,否则就走doMultiRealmAuthentication。
判断处理逻辑我们原来代码没有处理过多 realm 的经验,以前都是按照 doSingleRealmAuthentication 设计的返回值,当查不到用户时返回了 null。
单realm策略可以看到,当返回 null 时会抛出“未知用户异常”,这也是我们前端提示用户信息的事件源头。当换到多 realm 下,会发现异常被逻辑捕获了,放在了策略里处理。
多realm策略可以看到策略有几个接口,beforeAll,before,merge,after,afterAll,这些接口配合起来可以实现想要的配合逻辑。默认的策略是 LeastOneSuccessStrategy,默认返回了基础的异常,这也是我要处理的点,我重写了这个类,并且在前面的xml配置了这个自定义类,处理了异常类型。
至少成功一个策略当所有的realm执行完,如果用户信息为 null,那就是用户不存在。这是我们自己定义的业务逻辑,如果有自己的业务可以按照接口自行处理。
解决方案
总结一下,就是在多realm情况下,需要挑选或者自定义判断策略。例如
- 要求所有 realm 都要成功查到用户并且鉴权成功
- 只成功一个就可以(默认)
- 或者部分成功之类的
这里还要说到,大神们设计的很合理呀,流出了足够的自定义接口。
总结
这件事儿,让我知道自己掌握的知识太少了,涉及 shiro 鉴权流程的知识大脑一片空白。学习与工作都要一步一个脚印,这样下次回头的时候,才会有底气的说,我没有浪费我的人生。这也是我计划坚持写文的一个原因。
by 费城的二鹏 2020.05.01 写于道清
网友评论