shiro源碼分析


簡介

  • SecurityManager:安全管理器,Shiro最核心組件。Shiro通過SecurityManager來管理內部組件實例,並通過它來提供安全管理的各種服務。
  • Authenticator:認證器,認證AuthenticationToken是否有效。
  • Authorizer:授權器,處理角色和權限。
  • SessionManager:Session管理器,管理Session。
  • Subject:當前操作主體,表示當前操作用戶。
  • SubjectContext:Subject上下文數據對象。
  • AuthenticationToken:認證的token信息(用戶名、密碼等)。
  • ThreadContext:線程上下文對象,負責綁定對象到當前線程。

在學習和使用Shiro過程中,我們都知道SecurityManager接口在Shiro中是最為核心的接口。我們就沿着這個接口進行分析。

下面的代碼是SecurityManager接口的定義:

public interface SecurityManager extends Authenticator, Authorizer, SessionManager { /** * 登錄 */ Subject login(Subject subject, AuthenticationToken authenticationToken) throws AuthenticationException; /** * 登出 */ void logout(Subject subject); /** * 創建Subject */ Subject createSubject(SubjectContext context); } 

在SecurityManager 中定義了三個方法,分別是登錄、登出和創建Subject。通常我們在使用的時候是這樣使用的。首先創建Subject對象,然后通過調用login方法傳入認證信息token對登錄進行認證。

Subject subject = SecurityUtils.getSubject(); 
UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); subject.login(token); 

SecurityUtils分析

在Shiro中提供了一個方便使用的工具類SecurityUtils,SecurityUtils核心功能是獲取SecurityManager以及Subject。這兩個接口是Shiro提供的外圍接口,供開發時使用。

在SecurityUtils使用static定義SecurityManager,也就是說SecurityManager對象在應用中是單一存在的。

private static SecurityManager securityManager; 

1. 獲取SecurityManager

首先從ThreadContext中獲取,如果沒有,則從SecurityUtils屬性securityManager中獲取。一定要存在一個SecurityManager實例對象,否則拋異常。

public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException { SecurityManager securityManager = ThreadContext.getSecurityManager(); if (securityManager == null) { securityManager = SecurityUtils.securityManager; } if (securityManager == null) { String msg = "No SecurityManager accessible to the calling code, either bound to the " + ThreadContext.class.getName() + " or as a vm static singleton. This is an invalid application " + "configuration."; throw new UnavailableSecurityManagerException(msg); } return securityManager; } 

2. 獲取Subject

首先從ThreadContext中獲取,如果不存在,則創建新的Subject,再存放到ThreadContext中,以便下次可以獲取。

public static Subject getSubject() { Subject subject = ThreadContext.getSubject(); if (subject == null) { subject = (new Subject.Builder()).buildSubject(); ThreadContext.bind(subject); } return subject; } 

在上面的代碼中重要是通過 Subject.Builder類提供的buildSubject()方法來創建Subject。在創建Subject時同時還創建了SubjectContext對象,也就是說Subject和SubjectContext是一一對應的。下面的代碼是Subject.Builder類的構造方法。

public Builder(SecurityManager securityManager) { if (securityManager == null) { throw new NullPointerException("SecurityManager method argument cannot be null."); } this.securityManager = securityManager; // 創建了SubjectContext實例對象 this.subjectContext = newSubjectContextInstance(); if (this.subjectContext == null) { throw new IllegalStateException("Subject instance returned from 'newSubjectContextInstance' " + "cannot be null."); } this.subjectContext.setSecurityManager(securityManager); } 

而buildSubject()方法則實際上是調用SecurityManager接口中的createSubject(SubjectContext subjectContext)方法。

public Subject buildSubject() { return this.securityManager.createSubject(this.subjectContext); } 

總結

本篇主要通過SecurityUtils.getSubject()對SecurityManager接口中的createSubject(SubjectContext subjectContext)方法進行了詳細的分析。另外兩個方法我們在分析Subject時做詳細分析。

另外,我們會發現SecurityManager繼承了 Authenticator, Authorizer, SessionManager三個接口,這樣才能實現SecurityManager提供安全管理的各種服務。在接下來的文章中會對Authenticator, Authorizer, SessionManager分別進行分析,這樣我們對SecurityManager基本上就掌握了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM