Spring Security 自定義 (第二部分 - 即時調整安全會話)

工程 | Oleg Zhurakousky | 2009 年 1 月 3 日 | ...

想象一下您正在一個安全的會話中(您已登入並被授權訪問特定資源),但您的安全基礎設施團隊已更新了您的許可權。也許您獲得了更多許可權,或者您的許可權被完全撤銷了……問題是您的安全會話已在會話登錄檔中註冊,除非您登出/登入,否則代表您在此安全會話中的主體將不會被重新建立。如果情況更加嚴重呢(畢竟我們談論的是安全)……您是一名心懷不滿的員工,您的直接管理層發現了您的“不法行為”,但您的公司需要召開5次會議和10份審批表格才能完成某項工作,在此之前您可以自由地造成更大的傷害?

顯然,有許多業務場景可能需要在使用者處於會話中時調整其許可權。同樣在Spring Security中,顯然有不止一種方法可以實現此目的。一種方法是使用會話登錄檔(實際上是用於併發會話控制的)將人們踢出系統。透過構建GUI或啟用JMX,可以從已註冊會話列表中“過期”使用者。他們發出的下一個請求將被拒絕,並且會話將失效,從而強制執行身份驗證過程。然而,為了使其更有趣,也為了演示實現類似目標的另一種方法,讓我們稍微改變一下場景,假設我們不想完全使使用者的安全會話失效,而只是想暫時掛起它。

現在,在安全上下文中,“掛起”這個詞可能意味著許多不同的事情。它可能意味著暫時掛起,也可能意味著完全撤銷許可權。我將由您來定義這個詞在任何上下文中的含義……我更願意向您展示如何使用Spring Security元件(例如AccessDecisionVoterAccessDesisionManager)即時調整安全會話。此外,在以下示例中,我們將透過暫時掛起使用者的許可權而不使其會話失效來調整當前安全會話。

要實現此目的,我們需要遵循以下步驟。

1. 在Spring Security配置中定義AccessDecisionManager     1.1 定義基本投票器,例如RoleVoter和AuthenticatedVoter 2. 定義並實現AccessDecisionVoter。此投票器必須維護一個已被撤銷許可權的使用者列表,並且每次使用者執行安全操作時都必須投票ACCESS_DENIED。 3. 將此投票器新增到已註冊到AccessDecisionManager的投票器堆疊中。

此外,為了能夠在應用程式執行時與此投票器互動,我們還將使用Spring JMX將其動態匯出為JMX bean,從而啟用JMX。

差不多就是這樣。

所以,首先我們需要定義AccessDecisionManager (ADM)。由於我們使用Spring Security名稱空間(只要我們能用),像"security:http"這樣的配置元素,Spring Security將為我們註冊預設的AccessDecisionManager,它恰好是AffirmativeBased ADM。這對我們不利,因為我們在這裡試圖保守一點。所以,我們要做的是定義UnanimousBased ADM,並使用指向UnanimousBased ADM的access-decision-manager-ref屬性覆蓋"security:http"元素的預設ADM(見下文)

<!-- Define custom Voter --> <bean id="suspendVoter" class="org.springframework.security.sample.SuspendRealTimeVoter"/> <!-- Define AccessDesisionManager as UnanimousBased --> <bean id="accessDecisionManager" class="org.springframework.security.vote.UnanimousBased">   <property name="decisionVoters">     <list>       <ref bean="suspendVoter" />       <bean class="org.springframework.security.vote.RoleVoter" />       <bean class="org.springframework.security.vote.AuthenticatedVoter" />     </list>   </property> </bean>

我們還將把我們的自定義投票器放在投票器堆疊中的第一位,因為我們知道在基於一致的決策制定過程中,第一個“否”意味著不應執行進一步的評估。考慮到其他投票決策可能耗時或耗費效能,將自定義投票器首先註冊到投票器堆疊中將確保只有在許可權未暫停的情況下才執行此類投票操作。

<!-- 定義http安全配置 --> <security:http access-decision-manager-ref="accessDecisionManager" . . . . .> . . . . </security:http>

剩下唯一要做的事情就是啟用“suspendVoter”的JMX功能。這可以使用Spring JMX輕鬆完成。 <!-- 啟用自定義投票器的JMX --> <bean class="org.springframework.jmx.export.MBeanExporter">   <property name="beans">     <map>       <entry key="org.springframework.security:name=SuspendRealTimeVoter" value-ref="suspendVoter" />     </map>   </property> </bean>

現在,"suspendVoter"將以org.springframework.security:name=SuspendRealTimeVoter的名稱匯出到JMX伺服器中

從程式碼的角度來看,我們需要實現的唯一自定義元件是SuspendRealTimeVoter類。在該類中,我們將維護一個已暫時撤銷許可權的使用者集合。在vote(..)方法內部,我們的邏輯相當簡單。如果使用者在列表中,則投票ACCESS_DENIED,否則投票ACCESS_GRANTED。

public int vote(Authentication authentication, Object object, ConfigAttributeDefinition config) {     String userName = authentication.getName();     return revokedUsers.contains(userName) ? ACCESS_DENIED : ACCESS_GRANTED; }

您還將在其中看到suspend(String userName)grant(String userName)方法,我們將透過它們測試此功能。

注意:要透過JMX與我們的投票器互動,我們將使用JDK (1.5+)提供的JConsole工具,因此需要為我們的應用伺服器啟用JMX。對於此示例,我正在使用Tomcat,所以如果您正在使用Tomcat,請在其啟動指令碼中新增以下VM引數

-Dcom.sun.management.jmxremote

啟動伺服器,部署應用程式並訪問其URL:https://:8080/spring-security-sample-suspendUser

成功登入後,點選“重新整理”幾次,檢視您的會話是否正常執行。然後導航到JDK的bin目錄,開啟命令提示符並輸入jconsole(見下文)

當JConsole開啟時,點選MBeans選項卡。導航樹並訪問SuspendRealTimeVoter。

您將看到suspend(..)grant(..)方法在Operations選項卡下可用。掛起您登入的使用者的許可權,並重新整理您所在的HTML頁面。您將看到denied.html頁面。透過為該使用者呼叫grant(..)方法來取消掛起使用者,您將恢復正常。現在,如果確實需要5次會議和10份批准表格,您可以暫時撤銷使用者的許可權,給您的經理足夠的時間做出此類決定。

結論

這只是一個示例,演示瞭如何使用投票器暫時掛起安全會話。但我希望您能清楚地看到相同的Dota如何用於實現其他目標。這些目標可以是自動重新驗證使用者,或者只是更新他/她的GrantedAuthorities列表等等。

本文的示例原始碼可在此處下載:spring-security-sample-suspenduser

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有