1、Shiro认证过程 java
一、收集实体/凭据信息 apache
//Example using most common scenario of username/password pair: UsernamePasswordToken token = new UsernamePasswordToken(username, password); //”Remember Me” built-in: token.setRememberMe(true);
UsernamePasswordToken支持最多见的用户名/密码的认证机制。同时,因为它实现了RememberMeAuthenticationToken接口,咱们能够经过令牌设置“记住我”的功能。session
可是,“已记住”和“已认证”是有区别的: 架构
已记住的用户仅仅是非匿名用户,你能够经过subject.getPrincipals()获取用户信息。可是它并不是是彻底认证经过的用户,当你访问须要认证用户的功能时,你仍然须要从新提交认证信息。 ide
这一区别能够参考亚马逊网站,网站会默认记住登陆的用户,再次访问网站时,对于非敏感的页面功能,页面上会显示记住的用户信息,可是当你访问网站帐户信息时仍然须要再次进行登陆认证。工具
二、提交实体/凭据信息 网站
Subject currentUser = SecurityUtils.getSubject(); currentUser.login(token);
收集了实体/凭据信息以后,咱们能够经过SecurityUtils工具类(1),获取当前的用户(2),而后经过调用login方法提交认证(3)。 ui
三、认证处理spa
try { currentUser.login(token); } catch ( UnknownAccountException uae ) { ... } catch ( IncorrectCredentialsException ice ) { ... } catch ( LockedAccountException lae ) { ... } catch ( ExcessiveAttemptsException eae ) { ... } ... catch your own ... } catch ( AuthenticationException ae ) { //unexpected error? }
若是login方法执行完毕且没有抛出任何异常信息,那么便认为用户认证经过。以后在应用程序任意地方调用SecurityUtils.getSubject() 均可以获取到当前认证经过的用户实例,使用subject.isAuthenticated()判断用户是否已验证都将返回true. code
相反,若是login方法执行过程当中抛出异常,那么将认为认证失败。Shiro有着丰富的层次鲜明的异常类来描述认证失败的缘由,如代码示例。
2、登出操做
登出操做能够经过调用subject.logout()来删除你的登陆信息,如:
//removes all identifying information and invalidates their session too. currentUser.logout();
当执行完登出操做后,Session信息将被清空,subject将被视做为匿名用户。
3、认证内部处理机制
以上,是Shiro认证在应用程序中的处理过程,下面将详细解说Shiro认证的内部处理机制。
如上图,咱们经过Shiro架构图的认证部分,来讲明Shiro认证内部的处理顺序:
一、应用程序构建了一个终端用户认证信息的AuthenticationToken 实例后,调用Subject.login方法。
二、Sbuject的实例一般是DelegatingSubject类(或子类)的实例对象,在认证开始时,会委托应用程序设置的securityManager实例调用securityManager.login(token)方法。
三、SecurityManager接受到token(令牌)信息后会委托内置的Authenticator的实例(一般都是ModularRealmAuthenticator类的实例)调用authenticator.authenticate(token). ModularRealmAuthenticator在认证过程当中会对设置的一个或多个Realm实例进行适配,它实际上为Shiro提供了一个可拔插的认证机制。
四、若是在应用程序中配置了多个Realm,ModularRealmAuthenticator会根据配置的AuthenticationStrategy(认证策略)来进行多Realm的认证过程。在Realm被调用后,AuthenticationStrategy将对每个Realm的结果做出响应。
注:若是应用程序中仅配置了一个Realm,Realm将被直接调用而无需再配置认证策略。
五、判断每个Realm是否支持提交的token,若是支持,Realm将调用getAuthenticationInfo(token); getAuthenticationInfo 方法就是实际认证处理,咱们经过覆盖Realm的doGetAuthenticationInfo方法来编写咱们自定义的认证处理。
4、使用多个Realm的处理机制:
一、Authenticator
默认实现是ModularRealmAuthenticator,它既支持单一Realm也支持多个Realm。若是仅配置了一个Realm,ModularRealmAuthenticator 会直接调用该Realm处理认证信息,若是配置了多个Realm,它会根据认证策略来适配Realm,找到合适的Realm执行认证信息。
自定义Authenticator的配置:
[main] ... authenticator = com.foo.bar.CustomAuthenticator securityManager.authenticator = $authenticator
二、AuthenticationStrategy(认证策略)
当应用程序配置了多个Realm时,ModularRealmAuthenticator将根据认证策略来判断认证成功或是失败。
例如,若是只有一个Realm验证成功,而其余Realm验证失败,那么此次认证是否成功呢?
若是大多数的Realm验证成功了,认证是否就认为成功呢?
或者,一个Realm验证成功后,是否还须要判断其余Realm的结果?
认证策略就是根据应用程序的须要对这些问题做出决断。
认证策略是一个无状态的组件,在认证过程当中会通过4次的调用:
在全部Realm被调用以前
在调用Realm的getAuthenticationInfo 方法以前
在调用Realm的getAuthenticationInfo 方法以后
在全部Realm被调用以后
认证策略的另一项工做就是聚合全部Realm的结果信息封装至一个AuthenticationInfo实例中,并将此信息返回,以此做为Subject的身份信息。
Shiro有3中认证策略的具体实现:
ModularRealmAuthenticator 内置的认证策略默认实现是AtLeastOneSuccessfulStrategy 方式,由于这种方式也是被普遍使用的一种认证策略。固然,你也能够经过配置文件定义你须要的策略,如:
[main] ... authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy securityManager.authenticator.authenticationStrategy = $authcStrategy ...
三、Realm的顺序
由刚才提到的认证策略,能够看到Realm在ModularRealmAuthenticator 里面的顺序对认证是有影响的。
ModularRealmAuthenticator 会读取配置在SecurityManager里的Realm。当执行认证时,它会遍历Realm集合,对全部支持提交的token的Realm调用getAuthenticationInfo 。
所以,若是Realm的顺序对你使用的认证策略结果有影响,那么你应该在配置文件中明肯定义Realm的顺序,如:
blahRealm = com.company.blah.Realm ... fooRealm = com.company.foo.Realm ... barRealm = com.company.another.Realm securityManager.realms = $fooRealm, $barRealm, $blahRealm