上篇文章和小伙伴们分享了 JdbcRealm,本文我想和小伙伴们聊聊多 Realm 的认证策略问题。
多 Realm 认证策略
不知道小伙伴们是否还记得这张登录流程图:
从这张图中我们可以清晰看到 Realm 是可以有多个的,不过到目前为止,我们所有的案例都还是单 Realm,那么我们先来看一个简单的多 Realm 情况。
注意,本文的案例我们也是在前面案例的基础上完成,因此强烈建议小伙伴们阅读前文。
前面的文章我们自己创建了一个 MyRealm,也用过 JdbcRealm,但都是单独使用的,现在我想将两个一起使用,只需要修改 shiro.ini 配置即可,如下:
1 |
|
但是此时我数据库中用户的信息是 sang/123,MyRealm 中配置的信息也是 sang/123,我把 MyRealm 中的用户信息修改为 江南一点雨/456
,此时,我的 MyRealm 的 getAuthenticationInfo 方法如下:
1 |
|
这个时候我们就配置了两个 Realm,还是使用我们一开始的测试代码进行登录测试,这个时候我们发现我既可以使用 江南一点雨/456
进行登录,也可以使用 sang/123
进行登录,用 sang/123
登录成功之后用户的角色信息和之前是一样的,而用 江南一点雨/456
登录成功之后用户没有角色,这个也很好理解,因为我们在 MyRealm 中没有给用户配置任何权限。总而言之,就是当我有了两个 Realm 之后,现在只需要这两个 Realm 中的任意一个认证成功,就算我当前用户认证成功。
原理追踪
好了,有了上面的问题后,接下来我们在 Subject 的 login 方法上打断点,跟随程序的执行步骤,我们来到了 ModularRealmAuthenticator 类的 doMultiRealmAuthentication 方法中,如下:
1 |
|
在这个方法中,首先会获取当前一共有多少个 realm ,如果只有一个则执行 doSingleRealmAuthentication 方法进行处理,如果有多个 realm ,则执行 doMultiRealmAuthentication 方法进行处理。 doSingleRealmAuthentication 方法部分源码如下:
1 |
|
小伙伴们看到这里就明白了,这里调用了 realm 的 getAuthenticationInfo 方法,这个方法实际上就是我们自己实现的 MyRealm 中的 getAuthenticationInfo 方法。
那如果有多个 Realm 呢?我们来看看 doMultiRealmAuthentication 方法的实现,部分源码如下:
1 |
|
我这里主要来说下这个方法的实现思路:
- 首先获取多 Realm 认证策略
- 构建一个 AuthenticationInfo 用来存放一会认证成功之后返回的信息
- 遍历 Realm,调用每个 Realm 中的 getAuthenticationInfo 方法,看是否能够认证成功
- 每次获取到 AuthenticationInfo 之后,都调用 afterAttempt 方法进行结果合并
- 遍历完所有的 Realm 之后,调用 afterAllAttempts 进行结果合并,这里主要判断下是否一个都没匹配上
自由配置认证策略
OK,经过上面的简单解析,小伙伴们对认证策略应该有一个大致的认识了,那么在 Shiro 中,一共支持三种不同的认证策略,如下:
- AllSuccessfulStrategy,这个表示所有的Realm都认证成功才算认证成功
- AtLeastOneSuccessfulStrategy,这个表示只要有一个 Realm 认证成功就算认证成功,默认即此策略
- FirstSuccessfulStrategy,这个表示只要第一个 Realm 认证成功,就算认证成功
配置方式也很简单,在 shiro.ini 中进行配置,在上面配置的基础上,增加如下配置:
1 |
|
此时,我们再进行登录测试,则会要求每个 Realm 都认证通过才算认证通过。
好了,Realm 的认证策略问题,我们就先说到这里,有问题欢迎留言讨论。
本文案例下载地址:https://github.com/lenve/shiroSamples/archive/v5.zip