1. 程式人生 > >Spring Security學習筆記-自定義決策

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來實現。