Spring Security學習筆記-自定義決策
SpringSecutiry-自定義決策
當用戶身份認證通過後,會呼叫決策管理器判斷是否可以繼續訪問,圖中的AccessDecisionManager就是SpringSecurity的角色管理器,AbstractAccessDecisionManager,而我們要自定義角色管理器的話,一般是繼承抽象類而不是去實現介面。
public boolean supports(ConfigAttribute attribute) {
for (AccessDecisionVoter voter : this.decisionVoters) {
if (voter.supports (attribute)) {
return true;
}
}
return false;
}
supports()方法是AbstractAccessDecisionManager的核心方法。方法中有一個decisionVoters,它的型別是一個AccessDecisionVoter。
public interface AccessDecisionVoter<S> {
// ~ Static fields/initializers
// =====================================================================================
int ACCESS_GRANTED = 1;
int ACCESS_ABSTAIN = 0;
int ACCESS_DENIED = -1;
// ~ Methods
// =====================================================================================
boolean supports(ConfigAttribute attribute);
boolean supports(Class<?> clazz);
int vote(Authentication authentication, S object,
Collection<ConfigAttribute> attributes);
}
AccessDecisionVoter是SpringSecurity引入的投票器的概念,許可權訪問的最終決定權,就是由投票器來決定的。Security裡由許多投票器,最常見的投票器為RoleVoter。
public class RoleVoter implements AccessDecisionVoter<Object> {
// ~ Instance fields
// ========================================================================================
private String rolePrefix = "ROLE_";
// ~ Methods
// ===================================================================================
public String getRolePrefix() {
return rolePrefix;
}
/**
* Allows the default role prefix of <code>ROLE_</code> to be overridden. May be set
* to an empty value, although this is usually not desirable.
*
* @param rolePrefix the new prefix
*/
public void setRolePrefix(String rolePrefix) {
this.rolePrefix = rolePrefix;
}
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().startsWith(getRolePrefix())) {
return true;
}
else {
return false;
}
}
/**
* This implementation supports any type of class, because it does not query the
* presented secure object.
*
* @param clazz the secure object
*
* @return always <code>true</code>
*/
public boolean supports(Class<?> clazz) {
return true;
}
public int vote(Authentication authentication, Object object,
Collection<ConfigAttribute> attributes) {
if (authentication == null) {
return ACCESS_DENIED;
}
int result = ACCESS_ABSTAIN;
Collection<? extends GrantedAuthority> authorities = extractAuthorities(authentication);
for (ConfigAttribute attribute : attributes) {
if (this.supports(attribute)) {
result = ACCESS_DENIED;
// Attempt to find a matching granted authority
for (GrantedAuthority authority : authorities) {
if (attribute.getAttribute().equals(authority.getAuthority())) {
return ACCESS_GRANTED;
}
}
}
}
return result;
}
Collection<? extends GrantedAuthority> extractAuthorities(
Authentication authentication) {
return authentication.getAuthorities();
}
}
在RoleVoter中,定義了許可權的字首ROLE_,投票器的核心方法是vote()。vote方法中,authentication是使用者集許可權資訊,attributes是訪問資源需要的許可權,程式碼裡迴圈判斷使用者是否有訪問資源需要的許可權,有則返回ACCESS_GRANTED。SpringSecurity目前提供了三個決策投票器,第一個是AffirmativeBased,它的策略是一票通過,只要有一個投票器通過就允許訪問;第二個是ConConsensusBased,它的策略是有一半以上投票通過,才允許訪問資源;第三個UnanimousBased,它的策略是所有投票器都通過,才允許訪問資源。當我們自定義角色管理器時,我們繼承AbstractAccessDecisionManager這個類即可,並不是一定要使用投票器,也可以根據需要使用自己的投票器。如果我們訪問某個資源,需要同時擁有兩個或兩個以上許可權的情況時,我們就需要自定義AccessDecisionVoter來實現。