(一)//1、获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager
Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini")
2.factory类的类结构为:

(3)abstractFactory类主要设置是否单例
(4)iniFactorySupport是支持ini设置创建的对象
(5)iniSecuritymanagerFactory是ini方式创建securityManager的实现类
(二)//2、得到SecurityManager实例 并绑定给SecurityUtilsorg.apache.shiro.mgt.SecurityManagersecurityManager = factory.getInstance();
SecurityUtils.setSecurityManager(securityManager);
(1)通过创建的Ini对象创建Securitymanager对象
1 IniSecurityManagerFactory类: 2 creatSecuritymanager(ini){ 3 SecurityManager securityManager = createSecurityManager(ini); 4 return securityManager; 5 }
1 private SecurityManager createSecurityManager(Ini ini) { 2 //null 3 Ini.Section mainSection = ini.getSection(MAIN_SECTION_NAME); 4 if (CollectionUtils.isEmpty(mainSection)) { 5 6 //try the default: null 7 mainSection = ini.getSection(Ini.DEFAULT_SECTION_NAME); 8 } 9 return createSecurityManager(ini, mainSection); 10 }
(3)通过ini对象和主模块mainSession创建Securitymanager
1 private SecurityManager createSecurityManager(Ini ini, Ini.Section mainSection) { 2 //{securityManager=DefaultSecurityManager,iniRealm=IniRealm} 3 Map defaults = createDefaults(ini, mainSection); 4 Map objects = buildInstances(mainSection, defaults); 5 6 SecurityManager securityManager = getSecurityManagerBean(); 7 boolean autoApplyRealms = isAutoApplyRealms(securityManager); 8 if (autoApplyRealms) { 9 //realms and realm factory might have been created - pull them out first so we can initialize the securityManager: 10 Collection realms = getRealms(objects); 11 //set them on the SecurityManager 12 if (!CollectionUtils.isEmpty(realms)) { 13 applyRealmsToSecurityManager(realms, securityManager); 14 } 15 } 16 return securityManager; 17 }
1 private Map buildInstances(Ini.Section section, Map defaults) { 2 this.builder = new ReflectionBuilder(defaults); 3 return this.builder.buildObjects(section); 4 } 5 //类ReflectionBuilder 6 //通过mainSection创建对象并关联 7 public Map buildObjects(Map kvPairs) { 8 ..... 9 LifecycleUtils.init(objects.values()); 10 }
(5)因为IniRealm实现了Initializable,则初始化IniRealm对象
1 //类IniRealm 2 private void processDefinitions(Ini ini) { 3 Ini.Section usersSection = ini.getSection(USERS_SECTION_NAME); 4 processUserDefinitions(usersSection); 5 } 6 //通过userSection解析user模块 7 protected void processUserDefinitions(Map userDefs) { 8 for (String username : userDefs.keySet()) { 9 ........ 10 account = new SimpleAccount(username, password, getName()); 11 add(account); 12 ........ 13 } 14 } 15 protected void add(SimpleAccount account) { 16 String username = getUsername(account); 17 USERS_LOCK.writeLock().lock(); 18 try { 19 this.users.put(username, account); 20 }finally { 21 USERS_LOCK.writeLock().unlock(); 22 }
IniRealm的类结构为:

simpleAccount的结构为:

simpleAccount的结构为:
至此,创建对象关联,IniRealm的初始化完成!接下来看DefaultSecurityManager的结构图:
1 applyRealmsToSecurityManager(realms, securityManager){ 2 ((RealmSecurityManager) securityManager).setRealms(realms); 3 } 4 //在类RealmSecurityManager中 5 public void setRealms(Collection realms) { 6 this.realms = realms; 7 afterRealmsSet(); 8 }
注意:afterRealmsSet();主要用来设置authenticator、authorizer的realm属性:
至此DefaultSecurityManager的属性设置完成、并返回DefaultSecurityManager对象
//3、得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证)
Subject subject = SecurityUtils.getSubject();
1 //获取主题对象 2 public static Subject getSubject() { 3 Subject subject = ThreadContext.getSubject();//第一次null 4 if (subject == null) { 5 subject = (new Subject.Builder()).buildSubject(); 6 ThreadContext.bind(subject); 7 } 8 return subject; 9 }
(1)代码分析:使用建造者模式创建对象:
1 public static class Builder{ 2 SubjectContext subjectContext; 3 SecurityManager securityManager; 4 public Builder(SecurityManager securityManager) { 5 if (securityManager == null) { 6 throw new NullPointerException("SecurityManager method argument cannot be null."); 7 } 8 this.securityManager = securityManager; 9 this.subjectContext = newSubjectContextInstance();//DefaultSubjectContext(初始化一个backMap集合) 10 if (this.subjectContext == null) { 11 throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + 12 "cannot be null."); 13 } 14 this.subjectContext.setSecurityManager(securityManager); 15 } 16 public Subject buildSubject() { 17 return this.securityManager.createSubject(this.subjectContext); 18 } 19 }
(2)使用主题上下文创建主题
1 public Subject createSubject(SubjectContext subjectContext) { 2 //create a copy so we don't modify the argument's backing map: 3 SubjectContext context = copy(subjectContext); 4 5 //ensure that the context has a SecurityManager instance, and if not, add one: 6 context = ensureSecurityManager(context);//DefaultSubjectContext.backMap.put(SecurityManage) 7 8 //Resolve an associated Session (usually based on a referenced session ID), and place it in the context before 9 //sending to the SubjectFactory. The SubjectFactory should not need to know how to acquire sessions as the 10 //process is often environment specific - better to shield the SF from these details: 11 context = resolveSession(context); 12 13 //Similarly, the SubjectFactory should not require any concept of RememberMe - translate that here first 14 //if possible before handing off to the SubjectFactory: 15 context = resolvePrincipals(context); 16 17 Subject subject = doCreateSubject(context); 18 19 //save this subject for future reference if necessary: 20 //(this is needed here in case rememberMe principals were resolved and they need to be stored in the 21 //session, so we don't constantly rehydrate the rememberMe PrincipalCollection on every operation). 22 //Added in 1.2: 23 save(subject); 24 25 return subject; 26 }
(3)通过主题创建subject对象
protected Subject doCreateSubject(SubjectContext context) { return getSubjectFactory().createSubject(context); }
(4)DefaultSubjectFactory创建主题对象:
1 public Subject createSubject(SubjectContext context) { 2 SecurityManager securityManager = context.resolveSecurityManager(); 3 Session session = context.resolveSession(); 4 boolean sessionCreationEnabled = context.isSessionCreationEnabled(); 5 PrincipalCollection principals = context.resolvePrincipals(); 6 boolean authenticated = context.resolveAuthenticated(); 7 String host = context.resolveHost(); 8 9 return new DelegatingSubject(principals, authenticated, host, session, sessionCreationEnabled, securityManager); 10 }
到些sujbect对象创建完成,并把sujbect绑定到保存到本地变量和线程
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123");
//4、登录,即身份验证
subject.login(token);
(1)通过token登录.token失败,则抛出异常
public void login(AuthenticationToken token) throws AuthenticationException { ...... Subject subject = securityManager.login(this, token); ...... } //在DefaultSecurityManager中 public Subject login(Subject subject, AuthenticationToken token) throws AuthenticationException { try{AuthenticationInfo info = authenticate(token);}catch{...} Subject loggedIn = createSubject(token, info, subject); onSuccessfulLogin(token, info, loggedIn); return loggedIn; }
(2)多模块身份验证器类验证token(之前realm被设置于ModularRealmAuthenticator,只有一个iniRealm,故执行doSingleRealmAuthentication)
protected AuthenticationInfo doSingleRealmAuthentication(Realm realm, AuthenticationToken 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); } 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; }
(3)通过realm身份验证: