Shiro 測試

2021-06-21 10:43 更新

我們知道 Subject 是“當前執(zhí)行中”用戶的特定于安全性的視圖,并且 Subject 實例始終綁定到線程,以確保我們知道誰在任何時候都在執(zhí)行邏輯線程執(zhí)行期間的時間。

這意味著必須始終發(fā)生三件事,以支持能夠訪問當前正在執(zhí)行的 Subject:

  • 必須創(chuàng)建一個?Subject?實例
  • ?Subject?實例必須“綁定”到當前正在執(zhí)行的線程。
  • 線程完成執(zhí)行之后(或者如果線程的執(zhí)行結(jié)果為?Throwable?),則?Subject?必須為“未綁定” *,以確保線程在任何線程池化的環(huán)境中保持“干凈”。

Shiro 的體系結(jié)構(gòu)組件可為正在運行的應(yīng)用程序自動執(zhí)行此綁定/取消綁定邏輯。例如,在 Web 應(yīng)用程序中,根 Shiro 過濾器在過濾請求時執(zhí)行此邏輯。但是,由于測試環(huán)境和框架不同,我們需要針對所選測試框架自己執(zhí)行此綁定/解除綁定邏輯。

測試設(shè)置

因此,我們知道在創(chuàng)建?Subject?實例后,必須將其綁定到線程。在線程(或本例中為測試)完成執(zhí)行之后,我們必須* unbind * Subject 以保持線程“干凈”。

幸運的是,現(xiàn)代測試框架(如 JUnit 和 TestNG)本身已經(jīng)支持“設(shè)置”和“拆卸”這一概念。我們可以利用這種支持來模擬 Shiro 在“完整”應(yīng)用程序中將執(zhí)行的操作。我們已經(jīng)創(chuàng)建了一個基礎(chǔ)抽象類,您可以在下面的自己的測試中使用它-可以隨意復制和/或修改。它可以用于單元測試和集成測試(在此示例中,我們使用的是 JUnit,但是 TestNG 也可以工作):

因此,我們知道在創(chuàng)建Subject實例后,必須將其綁定到線程。在線程(或本例中為測試)完成執(zhí)行之后,我們必須* unbind * Subject 以保持線程“干凈”。

幸運的是,現(xiàn)代測試框架(如 JUnit 和 TestNG)本身已經(jīng)支持“設(shè)置”和“拆卸”這一概念。我們可以利用這種支持來模擬 Shiro 在“完整”應(yīng)用程序中將執(zhí)行的操作。我們已經(jīng)創(chuàng)建了一個基礎(chǔ)抽象類,您可以在下面的自己的測試中使用它-可以隨意復制和/或修改。它可以用于單元測試和集成測試(在此示例中,我們使用的是 JUnit,但是 TestNG 也可以工作):

Shiro測試摘要

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.subject.support.SubjectThreadState;
import org.apache.shiro.util.LifecycleUtils;
import org.apache.shiro.util.ThreadState;
import org.junit.AfterClass;

/**
 * Abstract test case enabling Shiro in test environments.
 */
public abstract class AbstractShiroTest {

    private static ThreadState subjectThreadState;

    public AbstractShiroTest() {
    }

    /**
     * Allows subclasses to set the currently executing {@link Subject} instance.
     *
     * @param subject the Subject instance
     */
    protected void setSubject(Subject subject) {
        clearSubject();
        subjectThreadState = createThreadState(subject);
        subjectThreadState.bind();
    }

    protected Subject getSubject() {
        return SecurityUtils.getSubject();
    }

    protected ThreadState createThreadState(Subject subject) {
        return new SubjectThreadState(subject);
    }

    /**
     * Clears Shiro's thread state, ensuring the thread remains clean for future test execution.
     */
    protected void clearSubject() {
        doClearSubject();
    }

    private static void doClearSubject() {
        if (subjectThreadState != null) {
            subjectThreadState.clear();
            subjectThreadState = null;
        }
    }

    protected static void setSecurityManager(SecurityManager securityManager) {
        SecurityUtils.setSecurityManager(securityManager);
    }

    protected static SecurityManager getSecurityManager() {
        return SecurityUtils.getSecurityManager();
    }

    @AfterClass
    public static void tearDownShiro() {
        doClearSubject();
        try {
            SecurityManager securityManager = getSecurityManager();
            LifecycleUtils.destroy(securityManager);
        } catch (UnavailableSecurityManagerException e) {
            //we don't care about this when cleaning up the test environment
            //(for example, maybe the subclass is a unit test and it didn't
            // need a SecurityManager instance because it was using only
            // mock Subject instances)
        }
        setSecurityManager(null);
    }
}

測試和框架

?AbstractShiroTest?類中的代碼使用 Shiro 的?ThreadState?概念和靜態(tài) SecurityManager。這些技術(shù)在測試和框架代碼中很有用,但很少在應(yīng)用程序代碼中使用。

大多數(shù)需要確保線程狀態(tài)一致性的與 Shiro 合作的最終用戶,幾乎都會使用 Shiro 的自動 Management 機制,即 Subject.associateWith 和 Subject.execute 方法。這些方法在主題線程關(guān)聯(lián)的參考中介紹。

以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號