shiro全局设置
1.获取SecurityManager工厂,读取ini文件
Factory<org.apache.shiro.mgt.SecurityManager> factory =new IniSecurityManagerFactory(configFile);
2.通过ini初始化实例,将配置好的的realm注入securityManager实例
org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance();
调用IniSecurityManagerFactory的createSecurityManager(Ini ini, Section mainSection)方法,调用this.isAutoApplyRealms(securityManager)
private SecurityManager createSecurityManager(Ini ini, Section mainSection) {
Map<String, ?> defaults = this.createDefaults(ini, mainSection);
Map<String, ?> objects = this.buildInstances(mainSection, defaults);
SecurityManager securityManager = this.getSecurityManagerBean();
boolean autoApplyRealms = this.isAutoApplyRealms(securityManager);
if (autoApplyRealms) {
Collection<Realm> realms = this.getRealms(objects);
if (!CollectionUtils.isEmpty(realms)) {
this.applyRealmsToSecurityManager(realms, securityManager);
}
}
return securityManager;
}
调用this.isAutoApplyRealms(securityManager)判断是否自动引入realm,有则继续
无则调用this.applyRealmsToSecurityManager(realms, securityManager);将realm注入securityManager
返回securityManager实例
3.绑定给SecurityUtils
SecurityUtils.setSecurityManager(securityManager);
4.通过 SecurityUtils 得到 Subject,其会自动绑定到当前线程;ThreadContext.bind(subject);
Subject subject = SecurityUtils.getSubject();
5. 应用代码通过 Subject 来进行认证和授权
认证:
代码调用
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
1.subject.login(token);
调用DelegatingSubject的login(AuthenticationToken token)方法进行认证
2.Subject subject = this.securityManager.login(this, token);
因为Subject不真正执行认证逻辑,又委托给 SecurityManager;
3.info = this.authenticate(token);
调用DefaultSecurityManager的login(Subject subject, AuthenticationToken token)方法,
4.this.authenticator.authenticate(token);
调用AuthenticatingSecurityManager的authenticate(AuthenticationToken token)方法
5.info = this.doAuthenticate(token);
SecurityManager 不负责真正的身份验证逻辑;它会委托给 Authenticator 进行身份验证;
调用AbstractAuthenticator的authenticate(AuthenticationToken token)
6.Authenticator 才是真正的身份验证者,默认调用ModularRealmAuthenticator的doAuthenticate(AuthenticationToken authenticationToken)方法,
在这个方法里,判断是多Realm认证,还是单Realm认证
protected AuthenticationInfo doAuthenticate(AuthenticationToken authenticationToken) throws AuthenticationException {
this.assertRealmsConfigured();
Collection<Realm> realms = this.getRealms();
return realms.size() == 1 ? this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken) : this.doMultiRealmAuthentication(realms, authenticationToken);
}
7.Authenticator 会把相应的 token 传入 Realm
realm.getAuthenticationInfo(token)
如果是单realm
1.this.doSingleRealmAuthentication((Realm)realms.iterator().next(), authenticationToken)
2.调用doSingleRealmAuthentication(Realm realm, AuthenticationToken token)
3.AuthenticationInfo info = realm.getAuthenticationInfo(token);
如果是多realm
Authenticator 可能会委托给相应的 AuthenticationStrategy 进行多 Realm 身份验证
调用doMultiRealmAuthentication(Collection<Realm> realms, AuthenticationToken token)
1.AuthenticationInfo aggregate = strategy.beforeAllAttempts(realms, token);
2.Iterator i$ = realms.iterator();
3.while(i$.hasNext()) {
aggregate = strategy.beforeAttempt(realm, token, aggregate);
4.info = realm.getAuthenticationInfo(token);
aggregate = strategy.afterAttempt(realm, token, info, aggregate, t);
}
5.aggregate = strategy.afterAllAttempts(token, aggregate);
8.从 Realm 获取身份验证信息
调用自定义Realm的doGetAuthenticationInfo(AuthenticationToken token)方法,获取reaml认证需要的信息
Realm里面是真正的验证逻辑