天天看點

Apache Shiro源碼(SecurityUtils)

源碼注釋

根據運作時環境,為調用代碼通路目前可通路的Subject。

由上可見,SecurityUtils主要是為了擷取Subject的,然後通過Subject進行一系列的驗證動作。

API

  1. private static volatile SecurityManager securityManager;
提供了一個靜态的私有變量SecurityManager,相當于一個程式的SecurityManager模闆,在目前線程記憶體儲的SecurityManager為空時,就傳回此變量。
  1. public static Subject getSubject(){…}
整個SecurityUtils的核心方法,從ThreadContext(基于ThreadLocal的存儲Subject和SecurityManager)擷取Subject。目前線程沒有Subject的話就建立一個Subject并放進ThreadContext中。
public static Subject getSubject() {
        Subject subject = ThreadContext.getSubject();
        if (subject == null) {
            subject = (new Subject.Builder()).buildSubject();
            ThreadContext.bind(subject);
        }
        return subject;
    }
           
  1. public static void setSecurityManager(SecurityManager securityManager) {…}
設定SecurityUtils.securityManager。
public static void setSecurityManager(SecurityManager securityManager) {
        SecurityUtils.securityManager = securityManager;
    }
           
  1. public static SecurityManager getSecurityManager() throws UnavailableSecurityManagerException {…}
先從ThreadContext(目前線程中)中擷取SecurityManager,如果不存在,就傳回SecurityUtils.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;
    }
           

1、為何getSecurityManager()方法中當ThreadContext的SecurityManager 為空時,傳回SecurityUtils.securityManager,但不将SecurityUtils.securityManager存進目前線程的ThreadContext中呢?那ThreadContext的SecurityManager什麼時候放進去的呢?

擴充

1、getSubject中的(new Subject.Builder()).buildSubject()解析:

Builder為Subject的靜态内部類,其内部有兩個私有final變量subjectContext和securityManager。subjectContext為DefaultSubjectContext,預設的securityManager為SecurityUtils.securityManager。
内部方法支援設定subjectContext的各個屬性值
  • public Builder sessionId(Serializable sessionId);

    設定subjectContext的SessionId。確定正在建構的Subject将使用指定的sessionId執行個體。

  • public Builder session(Session session);

    設定subjectContext的Session。確定正在建構的Subject将使用指定的Session執行個體。但是使用sessionId建構器方法比為該方法構造執行個體更常見。

  • public Builder host(String host);

    設定subjectContext的host。確定正在建構的Subject将反映指定的主機名或IP作為其起源的位置。

  • public Builder principals(PrincipalCollection principals);

    設定subjectContext的PrincipalCollection 。確定正在建構的Subject将反映指定的主體(又名辨別)。即建構此辨別的Subject。例:

PrincipalCollection identity = new
org.apache.shiro.subject.SimplePrincipalCollection(Object, String);
Subject jsmith = new Subject.Builder().principals(identity).buildSubject();
           
  • public Builder sessionCreationEnabled(boolean enabled);

    設定subjectContext的SessionCreationEnabled。配置建立的Subject執行個體的時候是否可以建立一個新的Session (如果不存在的話)。如果設定為false,任何對subject.getSession()或subject.getSession(true))的應用程式調用都會導緻SessionException。預設是true。

  • public Builder authenticated(boolean authenticated);

    設定目前建立的Subject執行個體是否應視為已驗證,如果為true,則org.apache.shiro.subject.Subject#isAuthenticated()傳回true。

  • public Builder contextAttribute(String attributeKey, Object attributeValue);

    将自定義屬性添加到底層上下文MapContext中,用于構造Subject執行個體。

  • public Subject buildSubject();

    建立一個Subject,調用的是目前Builder中SecurityManager的createSubject方法。

    this.securityManager.createSubject(this.subjectContext)

    後續代碼将在SecurityManager中進行分析。