今天想和大家聊一聊 Shiro 中的多 Realm 认证策略问题~
在项目中,如果我们想手机验证码登录、第三方 QQ 登录、邮箱登录等多种登录方式共存,那么就可以考虑通过 Shiro 中的多 Realm 来实现,具体操作中,一个 Realm 刚好就对应一种登录方式。
多 Realm 登录的用法并不难,松哥之前也专门发过相关的文章和大家分享,传送门:
其实我不仅会 Spring Security,Shiro 也略懂一二!
今天我不想聊用法,主要是想和大家聊一聊这里相关的源码。因此本文需要大家有一定的 Shiro 使用经验,若无,可以参考上面的链接恶补一下。
1. ModularRealmAuthenticator
1.1 Realm 去哪了?
我们配置的 Realm,可以直接配置给 SecurityManager,也可以配置给 SecurityManager 中的 ModularRealmAuthenticator。
如果我们是直接配置给 SecurityManager,那么在完成 Realm 的配置后,会自动调用 afterRealmsSet 方法,在该方法的中,会将我们配置的所有 Realm 最终配置给 ModularRealmAuthenticator。
相关源码如下:
RealmSecurityManager#setRealm(RealmSecurityManager 是 DefaultWebSecurityManager 的父类)
public void setRealm(Realm realm) { if (realm == null) { throw new IllegalArgumentException("Realm argument cannot be null"); } Collection
realms = new ArrayList
(1); realms.add(realm); setRealms(realms);}public void setRealms(Collection
realms) { if (realms == null) { throw new IllegalArgumentException("Realms collection argument cannot be null."); } if (realms.isEmpty()) { throw new IllegalArgumentException("Realms collection argument cannot be empty."); } this.realms = realms; afterRealmsSet();}
可以看到,无论是设置单个 Realm 还是设置多个 Realm,最终都会调用到 afterRealmsSet 方法,该方法在 AuthorizingSecurityManager#afterRealmsSet 类中被重写,内容如下:
protected void afterRealmsSet() { super.afterRealmsSet(); if (this.authorizer instanceof ModularRealmAuthorizer) { ((ModularRealmAuthorizer) this.authorizer).setRealms(getRealms()); }}
可以看到,所有的 Realm 最终都被设置给 ModularRealmAuthenticator 了。
所以说,无论是单个 Realm 还是多个 Realm,最终都是由 ModularRealmAuthenticator 统一管理统一调用的。
1.2 ModularRealmAuthenticator 怎么玩
ModularRealmAuthenticator 中核心的方法就是 doAuthenticate,如下:
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { assertRealmsConfigured(); Collection
realms = getRealms(); if (realms.size() == 1) { return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { return doMultiRealmAuthentication(realms, authenticationToken); }}
这个方法的逻辑很简单:
首先调用 assertRealmsConfigured 方法判断一下开发者有没有配置 Realm,要是没有配置就直接抛异常了。
判断开发者配置了几个 Realm,要是配置了一个,就调用 doSingleRealmAuthentication 方法进行处理,要是配置了多个 Realm 则调用 doMultiRealmAuthentication 方法进行处理。
配置一个 Realm 的情况比较简单,不在本文的讨论范围内,本文主要是想和大家讨论多个 Realm 的情况。
当存在多个 Realm 的时候,必然又会带来另一个问题:
认证策略
,即怎么样就算认证成功?一个 Realm 认证成功就算成功还是所有 Realm 认证成功才算成功?还是怎么样。
接下来我们来详细聊一聊这个话题。
2. AuthenticationStrategy
先来整体上看下,负责认证策略的类是 AuthenticationStrategy,这是一个接口,有三个实现类:
单从字面上来看,三个实现类都好理解:
AtLeastOneSuccessfulStrategy:至少有一个 Realm 认证成功。
AllSuccessfulStrategy:所有 Realm 都要认证成功。
FirstSuccessfulStrategy:这个从字面上理解不太准确,
它是只返回第一个认证成功的用户数据
。
第二种其实很好理解,问题在于第 1 个和第 3 个,这两个单独理解也好理解,放在一起的话,那有人不禁要问,这俩有啥区别?
老实说,在 1.3.2 之前的版本还真没啥大的区别,不过现在最新版本还是有些区别,且听松哥来分析。
首先这里一共涉及到四个方法:
beforeAllAttempts:在所有 Realm 验证之前的做准备。
beforeAttempt:在单个 Realm 之前验证做准备。
afterAttempt:处理单个 Realm 验证之后的后续事宜。
afterAllAttempts:处理所有 Realm 验证之后的后续事宜。
第一个和第四个方法在每次认证流程中只调用一次,而中间两个方法则在每个 Realm 调用前后都会被调用到,伪代码就类似下面这样:
上面这四个方法,在 AuthenticationStrategy 的四个实现类中有不同的实现,我整理了下面一张表格,方便大家理解:
大家注意这里多了一个 merge 方法,这个方法是在 AbstractAuthenticationStrategy 类中定义的,当存在多个 Realm 时,合并多个 Realm 中的认证数据使用的。接下来我们就按照这张表的顺序,来挨个分析这里的几个方法。
2.1 AbstractAuthenticationStrategy
2.1.1 beforeAllAttempts
直接来看代码吧:
public AuthenticationInfo beforeAllAttempts(Collection
- 最新留言
-
- 内容很有深度!http://v8lf.desaypower.com.cn/
- 楼上的别说的那么悲观好吧!http://282.desaypower.com.cn/
- 有钱、有房、有车,人人都想!http://1wo.zoneby-ep.cn/
- 看帖回帖一条路!http://vp0.zoneby-ep.cn/
- 刚看见一个妹子,很漂亮!http://jzgz4.zoneby-ep.cn/
- 支持一下,下面的保持队形!http://3bi.net/post/2705.html/
- 感谢楼主的推荐!http://3bi.net/post/2705.html/
- 我只看看不说话。。。http://3bi.net/post/2705.html/
- 祖国尚未统一,我却天天灌水,好内疚!http://3bi.net/post/2705.html/
- 楼主说的我也略懂!http://kp1.xmhmzx.com.cn/
- 文章归档
-
- 2025年5月 (102)
- 2025年4月 (371)
- 2025年3月 (377)
- 2025年2月 (338)
- 2025年1月 (389)
- 2024年12月 (374)
- 2024年11月 (361)
- 2024年10月 (374)
- 2024年9月 (360)
- 2024年8月 (381)
- 2024年7月 (388)
- 2024年6月 (370)
- 2024年5月 (372)
- 2024年4月 (363)
- 2024年3月 (375)
- 2024年2月 (355)
- 2024年1月 (394)
- 2023年12月 (376)
- 2023年11月 (366)
- 2023年10月 (711)
- 2023年9月 (2758)
- 2023年8月 (2837)
- 2023年7月 (2637)
- 2023年6月 (2433)
- 2023年5月 (3416)
- 2023年4月 (3248)
- 2023年3月 (3478)
- 2023年2月 (3105)
- 2023年1月 (3491)
- 2022年12月 (3470)
- 2022年11月 (2403)
- 2022年10月 (2253)
- 2022年9月 (1263)
- 2022年8月 (1298)
- 2022年7月 (1495)
- 2022年6月 (1954)
- 2022年5月 (2930)
- 2022年4月 (2604)
- 2022年3月 (1050)
- 2022年1月 (2774)
- 2021年12月 (2199)
- 2021年11月 (2905)
- 2021年10月 (1319)
- 2021年9月 (1822)
Powered By Z-BlogPHP,Theme By 冀ICP备2022013555号,Copyright Your WebSite.Some Rights Reserved.