5.Authenticator(登录验证器)
2015-09-06 23:37
363 查看
Authenticator在shiro中是主要负责验证用户登录,它通常和一组Realm来协调、交互验证用户登录。一般情况下我们不会直接使用Authenticator。而是交由SecurityManager来委托使用。
![](http://img.blog.csdn.net/20150907112310857)
1.Authenticator
2.AbstractAuthenticator
3.ModularRealmAuthenticator
1.Authenticator
[code]public interface Authenticator { //根据用户输入的AuthenticationToken(账号密码)然后去和底层数据库进行匹配验证登录。如果成功则返回AuthenticationInfo //(AuthenticationToken在数据库中对应的用户信息),失败则抛出异常 public AuthenticationInfo authenticate(AuthenticationToken authenticationToken) throws AuthenticationException; }
2.AbstractAuthenticator
[code]//Authenticator的顶层抽象类,该类没有实现具体的用户登录验证逻辑,只是提供了一些通知功能。如登录成功、登录失败或者退出时候, //则迭代调用AuthenticationListener的onSuccess、onFailure、onLogout方法执行用户自定义的逻辑操作 public abstract class AbstractAuthenticator implements Authenticator, LogoutAware { private static final Logger log = LoggerFactory.getLogger(AbstractAuthenticator.class); //用户注册的AuthenticationListener(里面有onSuccess、onFailure、onLogout方法) private Collection<AuthenticationListener> listeners; /*------------------------------------------- | C O N S T R U C T O R S | ============================================*/ public AbstractAuthenticator() { listeners = new ArrayList<AuthenticationListener>(); } /*-------------------------------------------- | A C C E S S O R S / M O D I F I E R S | ============================================*/ @SuppressWarnings({"UnusedDeclaration"}) public void setAuthenticationListeners(Collection<AuthenticationListener> listeners) { if (listeners == null) { this.listeners = new ArrayList<AuthenticationListener>(); } else { this.listeners = listeners; } } @SuppressWarnings({"UnusedDeclaration"}) public Collection<AuthenticationListener> getAuthenticationListeners() { return this.listeners; } /*------------------------------------------- | M E T H O D S | ============================================*/ //当用户登录验证成功时候,调用此方法迭代AuthenticationListener的onSuccess方法 protected void notifySuccess(AuthenticationToken token, AuthenticationInfo info) { for (AuthenticationListener listener : this.listeners) { listener.onSuccess(token, info); } } //当用户登录验证失败时候,调用此方法迭代AuthenticationListener的onFailure方法 protected void notifyFailure(AuthenticationToken token, AuthenticationException ae) { for (AuthenticationListener listener : this.listeners) { listener.onFailure(token, ae); } } //当用户退出时候,调用此方法迭代AuthenticationListener的onLogout方法 protected void notifyLogout(PrincipalCollection principals) { for (AuthenticationListener listener : this.listeners) { listener.onLogout(principals); } } //用户退出时候执行 public void onLogout(PrincipalCollection principals) { notifyLogout(principals); } //实现Authenticator的authenticate方法,验证用户登录 public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException { if (token == null) { throw new IllegalArgumentException("Method argumet (authentication token) cannot be null."); } log.trace("Authentication attempt received for token [{}]", token); AuthenticationInfo info; try { //调用子类实现的模板方法,执行真正的验证逻辑 info = doAuthenticate(token); if (info == null) { String msg = "No account information found for authentication token [" + token + "] by this " + "Authenticator instance. Please check that it is configured correctly."; throw new AuthenticationException(msg); } } catch (Throwable t) { AuthenticationException ae = null; //包装异常 if (t instanceof AuthenticationException) { ae = (AuthenticationException) t; } if (ae == null) { //Exception thrown was not an expected AuthenticationException. Therefore it is probably a little more //severe or unexpected. So, wrap in an AuthenticationException, log to warn, and propagate: String msg = "Authentication failed for token submission [" + token + "]. Possible unexpected " + "error? (Typical or expected login exceptions should extend from AuthenticationException)."; ae = new AuthenticationException(msg, t); } try { //验证失败,调用失败通知 notifyFailure(token, ae); } catch (Throwable t2) { if (log.isWarnEnabled()) { String msg = "Unable to send notification for failed authentication attempt - listener error?. " + "Please check your AuthenticationListener implementation(s). Logging sending exception " + "and propagating original AuthenticationException instead..."; log.warn(msg, t2); } } throw ae; } log.debug("Authentication successful for token [{}]. Returned account [{}]", token, info); //执行到这里,代表用户验证成功,则调用验证成功通知 notifySuccess(token, info); return info; } //模板方法,子类实现的真正的验证逻辑 protected abstract AuthenticationInfo doAuthenticate(AuthenticationToken token) throws AuthenticationException; }
3.ModularRealmAuthenticator
[code]/** PAM(Pluggable Authentication Module):PAM是一个聚合底层的验证服务模块的高级API 每一个底层的验证服务模块都可以作为一个验证方案,可根据需求来配置集合成一个验证 服务。 ModularRealmAuthenticator继承于AbstractAuthenticator,也属于PAM里的一个验证服务模块,用户可根据 需求来自定义Realm,然后插入到ModularRealmAuthenticator的realms。 如果用户配置多个Realm时,用户可配置Realm的使用策略,如:至少一个Realm验证成功(AtLeastOneSuccessfulStrategy), 或者必须所有的Realm都成功(AllSuccessfulStrategy),来决定后续的逻辑操作。 **/ public class ModularRealmAuthenticator extends AbstractAuthenticator { private static final Logger log = LoggerFactory.getLogger(ModularRealmAuthenticator.class); //Realm集合,用于用户登陆验证时候 private Collection<Realm> realms; //配置多个Realm使用策略 private AuthenticationStrategy authenticationStrategy; /*-------------------------------------------- | C O N S T R U C T O R S | ============================================*/ public ModularRealmAuthenticator() { //默认多个Realm使用策略:AtLeastOneSuccessfulStrategy(至少一个成功) this.authenticationStrategy = new AtLeastOneSuccessfulStrategy(); } //设置Realms,提供PAM配置支持 public void setRealms(Collection<Realm> realms) { this.realms = realms; } protected Collection<Realm> getRealms() { return this.realms; } public AuthenticationStrategy getAuthenticationStrategy() { return authenticationStrategy; } //覆盖默认多Realm使用策略 public void setAuthenticationStrategy(AuthenticationStrategy authenticationStrategy) { this.authenticationStrategy = authenticationStrategy; } //确保Realms不为空,至少需要一个,否则抛异常。 protected void assertRealmsConfigured() throws IllegalStateException { Collection<Realm> realms = getRealms(); if (CollectionUtils.isEmpty(realms)) { String msg = "Configuration error: No realms have been configured! One or more realms must be " + "present to execute an authentication attempt."; throw new IllegalStateException(msg); } } //单个Realm执行的验证逻辑 protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken token) { //首先判断Realm是否支持该token if (!realm.supports(token)) { String msg = "Realm [" + realm + "] does not support authentication token [" + token + "]. Please ensure that the appropriate Realm implementation is " + "configured correctly or that the realm accepts AuthenticationTokens of this type."; throw new UnsupportedTokenException(msg); } //realm调用getAuthenticationInfo(token)来执行真正的数据验证交互。该方法如果验证失败会抛出相对应异常 AuthenticationInfo info = realm.getAuthenticationInfo(token); if (info == null) { String msg = "Realm [" + realm + "] was unable to find account data for the " + "submitted AuthenticationToken [" + token + "]."; throw new UnknownAccountException(msg); } return info; } //执行多个Realm验证逻辑 protected AuthenticationInfo doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token) { //获取多个Realm使用策略 AuthenticationStrategy strategy = getAuthenticationStrategy(); /** 以下的AuthenticationStrategy的方法我只针对AtLeastOneSuccessfulStrategy来说!!! **/ //执行所有Realm之前,AuthenticationStrategy首先初始化个SimpleAuthenticationInfo AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token); if (log.isTraceEnabled()) { log.trace("Iterating through {} realms for PAM authentication", realms.size()); } for (Realm realm : realms) { //执行单个Realm之前,直接返回aggregate aggregate = strategy.beforeAttempt(realm, token, aggregate); //Realm先判断是否支持该token if (realm.supports(token)) { log.trace("Attempting to authenticate token [{}] using realm [{}]", token, realm); AuthenticationInfo info = null; Throwable t = null; try { //realm调用真正的验证登陆处理逻辑 info = realm.getAuthenticationInfo(token); } catch (Throwable throwable) { t = throwable; if (log.isDebugEnabled()) { String msg = "Realm [" + realm + "] threw an exception during a multi-realm authentication attempt:"; log.debug(msg, t); } } //单个Realm执行之后,合并info和aggregate aggregate = strategy.afterAttempt(realm, token, info, aggregate, t); } else { log.debug("Realm [{}] does not support token {}. Skipping realm.", realm, token); } } //所有Realm执行之后,判断是否aggregate的getPrincipals是否为空,因为至少需要一个验证成功,所以为空则抛出异常 aggregate = strategy.afterAllAttempts(token, aggregate); //执行到这里,至少有一个Realm登陆验证成功。 return aggregate; } //实现Authenticator的authenticate方法 protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException { //首先验证realm是否为空 assertRealmsConfigured(); Collection<Realm> realms = getRealms(); if (realms.size() == 1) { //单个realm则执行单realm逻辑处理 return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken); } else { //处理多realm逻辑处理(依据AuthenticationStrategy) return doMultiRealmAuthentication(realms, authenticationToken); } } //退出时候调用 public void onLogout(PrincipalCollection principals) { //首先调用父类的onLogout,调用退出通知 super.onLogout(principals); Collection<Realm> realms = getRealms(); if (!CollectionUtils.isEmpty(realms)) { for (Realm realm : realms) { //迭代Realm执行退出方法,主要是清理缓存 if (realm instanceof LogoutAware) { ((LogoutAware) realm).onLogout(principals); } } } } }
相关文章推荐
- win10系统下,android studio里,Android签名证书的sha1值的获取。
- 素数 专题
- POJ 2502 Subway
- 分布式集群系统下的高可用session解决方案
- 正则化方法:L1和L2 regularization、数据集扩增、dropout
- HDU 5428 The Factor (素因数分解)
- WPF Step By Step 系列-Prism框架在项目中使用
- 阿里云 Linux 系统挂载数据盘:适用系统:Linux(Redhat , CentOS,Debian,Ubuntu)
- SRAM与DRAM区别
- 下半部和下半部执行的工作--工作队列
- ServiceLocator是反模式
- css.day01
- WPF Step By Step 自定义模板
- WPF Step By Step 完整布局介绍
- studio 快捷键
- 一个API接口的例子,包括单元测试
- 数组在java中的声明和应用
- Ruby:字符串处理函数
- WPF Step By Step 控件介绍
- 从委托、匿名方法到Lambda