1、获取从请求中传来的信息(一般是账号和密码),存进UsernamePasswordToken中
UsernamePasswordToken token = new UsernamePasswordToken(username, password)
2、从SecurityUtils中通过getSubject()方法获取登录的主体
Subject subject = SecurityUtils.getSubject();
3、然后执行登录的逻辑
subject.login(token);
4、DelegatingSubject继承与Subject,因此DelegatingSubject重写了Subject的非抽象方法login,如下
public void login(AuthenticationToken token) throws AuthenticationException {
clearRunAsIdentitiesInternal();
Subject subject = securityManager.login(this, token);
PrincipalCollection principals;
String host = null;
if (subject instanceof DelegatingSubject) {
DelegatingSubject delegating = (DelegatingSubject) subject;
//we have to do this in case there are assumed identities - we don't want to lose the 'real' principals:
principals = delegating.principals;
host = delegating.host;
} else {
principals = subject.getPrincipals();
}
if (principals == null || principals.isEmpty()) {
String msg = "Principals returned from securityManager.login( token ) returned a null or " +
"empty value. This value must be non null and populated with one or more elements.";
throw new IllegalStateException(msg);
}
this.principals = principals;
this.authenticated = true;
if (token instanceof HostAuthenticationToken) {
host = ((HostAuthenticationToken) token).getHost();
}
if (host != null) {
this.host = host;
}
Session session = subject.getSession(false);
if (session != null) {
this.session = decorate(session);
} else {
this.session = null;
}
}
上述代码中有一句此行代码:Subject subject = securityManager.login(this, token);subject的login方法其实调用的是SecurityManager的login方法
5、SecurityManager的login方法
public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException {
AuthenticationInfo info;
try {
info = authenticate(token);
} catch (AuthenticationException ae) {
try {
onFailedLogin(token, ae, subject);
} catch (Exception e) {
if (log.isInfoEnabled()) {
log.info("onFailedLogin method threw an " +
"exception. Logging and propagating original AuthenticationException.", e);
}
}
throw ae; //propagate
}
Subject loggedIn = createSubject(token, info, subject);
onSuccessfulLogin(token, info, loggedIn);
return loggedIn;
}
上述代码中info = authenticate(token);调用的其实是认证器(Authenticator)的认证方法(authenticate),此时由登录(login)转为认证(authenticate),在authenticate方法下调用的是认证器的doAuthenticate方法,如下
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
assertRealmsConfigured();
//获取Realm的集合,如果只有一个Realm,那么就按照单个流程处理,如果有多个,那么就按照多个流程去认证
Collection<Realm> realms = getRealms();
if (realms.size() == 1) {
return doSingleRealmAuthentication(realms.iterator().next(), authenticationToken);
} else {
return doMultiRealmAuthentication(realms, authenticationToken);
}
}
6、doSingleRealmAuthentication()方法和doMultiRealmAuthentication()方法
在第5步中获取Realm之后,会按照Realm的数量多少走认证流程,其实此两个方法的底层调用的是Realm的doGetAuthenticationInfo方法,此方法是认证的核心,如果认证成功,则将认证通过的信息装到shiro的AuthenticationInfo(SimpleAuthenticationInfo)中,如果认证失败,则抛出异常。