HTTP 請求經 FilterSecurityInterceptor.doFilter() 攔截,封裝為 FilterInvocation 呼叫 invoke()。首次請求設定 FILTER_APPLIED 屬性避免重複檢查,隨後呼叫父類 AbstractSecurityInterceptor.beforeInvocation() 執行核心授權邏輯。
ObjectDefinitionSource 讀取配置的 ConfigAttributeDefinition(如角色要求)。若為 null 且 rejectPublicInvocations=true 則拒絕存取。SecurityContextHolder 取得 Authentication。若不存在或未認證,委派 AuthenticationManager 認證,成功後存回 SecurityContextHolder。AccessDecisionManager.decide(authentication, object, attr)。失敗拋 AccessDeniedException 並發布 AuthorizationFailureEvent;成功發布 AuthorizedEvent。RunAsManager 可替換當前 Authentication(預設 NullRunAsManager 清空)。返回 InterceptorStatusToken 供 afterInvocation 使用。預設決策管理器遍歷配置的 AccessDecisionVoter 投票:
ACCESS_GRANTED → 立即通過。ACCESS_DENIED → 計數,最終若有反對票則拋出異常。ACCESS_ABSTAIN → 依 allowIfAllAbstainDecisions 決定(預設拒絕)。遍歷資源配置屬性,支援 ROLE_ 前綴角色。檢查使用者 GrantedAuthority[] 中是否包含匹配角色,若有則返回 ACCESS_GRANTED,否則 ACCESS_DENIED。若無支援屬性則棄權。
public int vote(Authentication auth, Object obj, ConfigAttributeDefinition config) {
int result = ACCESS_ABSTAIN;
for (ConfigAttribute attr : config.getConfigAttributes()) {
if (supports(attr)) {
result = ACCESS_DENIED;
for (GrantedAuthority ga : auth.getAuthorities()) {
if (attr.getAttribute().equals(ga.getAuthority()))
return ACCESS_GRANTED;
}
}
}
return result;
}
授權流程:FilterSecurityInterceptor 攔截 → 讀取資源屬性 → 確保認證 → AccessDecisionManager 協調多 Voter 投票 → RoleVoter 基於角色匹配決策 → 發布事件/處理 RunAs。架構清晰分離攔截、認證、授權、決策、投票職責,支援靈活擴展。