登录
Subject结构
首先看下我们在使用登录时用到的Subject结构:
可以看到,这个接口的功能就是与登录登出、权限鉴定相关;
另外,这个接口被WebSubject继承,这也是个接口,同时还继承了RequestPairSource,为Subject添加了获取Request和Response的能力。下面是它的结构:
对Subject接口的实现类有两个:DelegatingSubject 和 WebDelegatingSubject,继承关系如下:
关于登录和权限鉴定的功能都在 DelegatingSubject 中实现,而 WebDelegatingSubject 增加的功能都是和获取请求Request和响应Response实例相关。
登录--login
接下来看下DelegateSubject的 login实现:
public void login(AuthenticationToken token) throws AuthenticationException {
clearRunAsIdentitiesInternal();//清楚放在Session中的属性
//执行的登录的主要逻辑实现处
Subject subject = securityManager.login(this, token);
//后面代码功能为:获取登陆后的认证信息,设置当前登录状态和对Session进行进一步的包装
//略……
}
可以看到,登录的实现托付给了 SecurityManager 来实现,具体实现类是DefaultSecurityManager,实现如下:
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = authenticate(token); //执行登录
} catch (AuthenticationException ae) {
//登录失败时的处理(省略try/catch结构)
onFailedLogin(token, ae, subject);
throw ae; //propagate
}
//登录成功后的处理
Subject loggedIn = createSubject(token, info, subject);
onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
执行登录到逻辑放到了 authenticate 中:
可以看出,登录的逻辑又再一次被委托到了专门的认证器(Authenticator)中,我们直接看下它的实现类(
ModularRealmAuthenticator)源码:
public final AuthenticationInfo authenticate(AuthenticationToken token) throws AuthenticationException {
if (token == null) {
throw new IllegalArgumentException("Method argument (authentication token) cannot be null.");
}
AuthenticationInfo info;
try {
//执行 token 验证
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) {
//并非是Shiro抛出的登录相关异常,Shiro的处理是将其包装成AuthenticationException,打印warn日志,并返回错误信息
//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);
if (log.isWarnEnabled())
log.warn(msg, t);
}
//主要是通知相关的监听器 listens 处理登录失败的结果(省略try、catch)
notifyFailure(token, ae);
throw ae;//抛出异常
}
log.d