Spring Security 鑒權(quán)原理
1. 前言
在前面的章節(jié)里,我們討論了 Spring Security 如何實現(xiàn)「認證」,本節(jié)開始,我們進入 Spring Security 的「鑒權(quán)」部分。
鑒權(quán)(Authorization)是指驗證用戶是否擁有訪問系統(tǒng)的權(quán)力,它的前提是用戶的身份已經(jīng)得到有效地認證,也是認證的目標。
Spring Security 提供的鑒權(quán)能力的最大特點是,無關(guān)于開發(fā)人員所選用的認證方式(密碼認證、OAuth2.0 認證、證書認證等),即使它不是在 Spring Security 認證范圍之內(nèi)(預認證等),也可以簡單快捷的基礎 Spring Security 鑒權(quán)功能。
本節(jié)我們主要討論 Spring Security 關(guān)于鑒權(quán)部分的實現(xiàn)思路。
2. Spring Security 鑒權(quán)框架
2.1 權(quán)限
Spring Security 中,在用戶身份信息得到確認后,Authentication 中會存儲一系列的 GrantedAuthority 對象,這些對象用來判斷用戶可以使用哪些資源。
GrantedAuthority 對象通過 AuthenticationManager 插入到 Authentication 對象中,并被 AccessDecisionManager 使用,判斷其權(quán)限。
GrantedAuthority 是一個接口,其僅包含一個方法:
String getAuthority();
getAuthority()
方法返回一個字符串值,該值作為權(quán)限的描述,當權(quán)限較為復雜,不是字符串可以描述的情況時,該方法需要返回 null
。這種復雜的權(quán)限可能是「多種操作對應多個不同用戶」等類似情況,用一個字符串很難表達完整,此時 AccessDecisionManager 會根據(jù) getAuthority()
返回值情況判斷是否要進行特殊處理。
在 Spring Security 中,GrantedAuthority 有一個基礎實現(xiàn)類 SimpleGrantedAuthority
可以滿足一般的業(yè)務需求。
2.2 前置鑒權(quán)
Spring Security 的權(quán)限判斷可以發(fā)生在方法被調(diào)用前,或者 WEB 請求之前。在請求的開始,由 AccessDecisionManager
對象將判斷其是否允許繼續(xù)執(zhí)行。
AccessDecisionManager
對象由 AbstractSecurityInterceptor
發(fā)起調(diào)用,其職責是給出資源是否能被訪問的最終結(jié)果,AccessDecisionManager
包含三個主要方法:
- 判斷配置屬性是否可被訪問;
boolean supports(ConfigAttribute attribute);
- 判斷安全對象的類型是否支持被訪問;
boolean supports(Class clazz);
- 通過認證信息、安全對象、權(quán)限信息綜合判斷安全對象是否允許被訪問。
void decide(Authentication authentication, Object secureObject,
Collection<ConfigAttribute> attrs) throws AccessDeniedException;
Spring Security 的鑒權(quán)策略可以由用戶自己實現(xiàn),在 Spring Security 內(nèi)部也實現(xiàn)了一套鑒權(quán)策略,稱為「基于投票的訪問決策管理」。
在這種策略下,AccessDecisionManager
控制著一系列的 AccessDecisionVoter
實例,判斷權(quán)限是否滿足,如果不滿足拋出 AccessDeniedException
異常。
AccessDecisionVoter
也包含三個方法:
- 判斷配置屬性是否支持;
boolean supports(ConfigAttribute attribute);
- 判斷類型是否支持;
boolean supports(Class clazz);
- 根據(jù)認證信息對安全資源進行投票。
int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attrs);
投票鑒權(quán)分為三類:
- 基于角色的投票:RoleVoter;
- 基于認證信息的投票:AuthenticatedVoter,主要區(qū)分認證用戶、匿名用戶等;
- 自定義投票策略。
2.3 后置鑒權(quán)
有時候,權(quán)限的判斷是在資源被調(diào)動之后才處理的,此過程就是后置鑒權(quán)。
在 Spring Security 中,后置鑒權(quán)通過 AfterInvocationManager
進行管理。
后置鑒權(quán)在資源被訪問后,根據(jù)權(quán)限的判定來修改返回的內(nèi)容,或者返回 AccessDeniedException
。
2.4 多級角色
有時候,一個角色可能涵蓋了多種其他角色。例如:admin 可能包含 user 的權(quán)限,為實現(xiàn)這一功能,我們可能會為 admin 用戶增加 user 角色。
要實現(xiàn)這種配置,我們需要用到 RoleVoter 的擴展實現(xiàn)類,RoleHierarchyVoter
。其配置方式如下:
<bean id="roleVoter" class="org.springframework.security.access.vote.RoleHierarchyVoter">
<constructor-arg ref="roleHierarchy" />
</bean>
<bean id="roleHierarchy"
class="org.springframework.security.access.hierarchicalroles.RoleHierarchyImpl">
<property name="hierarchy">
<value>
ROLE_ADMIN > ROLE_STAFF
ROLE_STAFF > ROLE_USER
ROLE_USER > ROLE_GUEST
</value>
</property>
</bean>
這個配置中出現(xiàn)了四種角色,ADMIN、STAFF、USER、GUEST,而這四種又有明顯的包含于被包含關(guān)系,如此便可以使角色投票機制根據(jù)角色的層級進行決策。
3. 小結(jié)
本節(jié)我們討論了 Spring Security 中鑒權(quán)的基本設計思路,主要內(nèi)容如下:
- Spring Security 包含確認身份和確認身份的可執(zhí)行操作兩部分,后者即為鑒權(quán);
- Spring Security 的權(quán)限默認是以字符串形式存儲的權(quán)限信息,比如角色名稱、功能名稱等;
- Spring Security 內(nèi)置了以「投票」為判定方法的鑒權(quán)策略。
下節(jié)我們討論如何為 Servlet 應用提供鑒權(quán)能力。