Shiro的登录动作是由Subject
接口的 login(AuthenticationToken token)
方法进行的,而login()
方法的只有DelegatingSubject
实现了这个方法。
public void login(AuthenticationToken token) throws AuthenticationException {
clearRunAsIdentitiesInternal();
Subject subject = securityManager.login(this, token);
// Omit the more code(省略更多代码,Omit : 省略)
}
在 login()
方法中又调用了 SecurityManager
接口的 login
方法,该方法的实现由 DefaultSecurityManager
类实现。
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
// 执行 认证方法(authenticate)
info = authenticate(token);
} catch (AuthenticationException ae) {
// Omit the more code ···
}
}
一直追下去,authenticate
方法又调用了 AbstractAuthenticator
的 authenticate
方法。下面是该方法的实现。
AbstractAuthenticator
是 Shiro 鉴权的顶级接口Authenticator
的抽象实现类,Shiro 在Authenticator
接口的注释中(只有下载了源码才会看见)给出了 6 种鉴权异常,可用于鉴权过程中出现错误抛出。
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
if (token == null) {
throw new IllegalArgumentException("Method argument (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) {
// Omit the more code
}
}
在进行身份验证时的 doAuthenticate(token)
方法是 AbstractAuthenticator
定义的抽象方法,由 ModularRealmAuthenticator
类实现,由此可见AbstractAuthenticator
采用了 模板方法模式 来进行身份的校验。
模板方法模式是类的行为模式。准备一个抽象类,将部分逻辑以具体方法以及具体构造函数的形式实现,然后声明一些抽象方法来迫使子类实现剩余的逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法模式的用意。
比如定义一个操作中的算法的骨架,将步骤延迟到子类中。模板方法使得子类能够不去改变一个算法的结构即可重定义算法的某些特定步骤。
————————————————
版权声明:本文为优快云博主「炸斯特」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.youkuaiyun.com/jason0539/article/details/45037535
继续查看 doAuthenticate(AuthenticationToken authenticationToken)
的实现代码:
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
可以看到,如果只有一个 Realm 就会调用 doSingleRealmAuthentication(Realm realm, AuthenticationToken token)
如果有多个 Realm 就会调用 doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token)
通过查看这两个方法的实现,发现无论哪个方法都会调用 Realm
的
AuthenticationInfo getAuthenticationInfo(AuthenticationToken token)
public final AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
// 先从缓存中获取
AuthenticationInfo info = getCachedAuthenticationInfo(token);
// 如果缓存中没找到会从 Realm 的 doGetAuthenticationInfo 中获取
if (info == null) {
//otherwise not cached, perform the lookup:
info = doGetAuthenticationInfo(token);
log.debug("Looked up AuthenticationInfo [{}] from doGetAuthenticationInfo", info);
if (token != null && info != null) {
cacheAuthenticationInfoIfPossible(token, info);
}
} else {
log.debug("Using cached authentication info [{}] to perform credentials matching.", info);
}
if (info != null) {
assertCredentialsMatch(token, info);
} else {
log.debug("No AuthenticationInfo found for submitted AuthenticationToken [{}]. Returning null.", token);
}
return info;
}
注意这一行代码:info = doGetAuthenticationInfo(token);
这个方法名是不是很熟悉??? 使用 IDEA command + 左键查看实现,红色框起来的就是我们自定义的 Realm
。
Ps: doAuthenticate(AuthenticationToken token)
方法也是采用的模板方法模式 。