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来实现。

猜你喜欢

转载自blog.csdn.net/qq_41620800/article/details/84829424