spring security访问控制决策管理器

在这里插入图片描述
我们先来看下类图。顶层接口为 AccessDecisionManager,仅有一个抽象实现,三个具体实现类继承自抽象类。

  • AffirmativeBased 一票通过制
  • ConsensusBased 半数以上通过制
  • UnanimousBased 全数通过制
    见名知意,不用我多解释了。
    在这几个决策器中调用投票器AccessDecisionVoter,进行投票。
    RoleVoter投票器的逻辑如下:
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) {
		//判断是否以ROLE_开头(根据不同的业务不同)
			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;
	}

投票器的三个常量

  • ACCESS_ABSTAIN 0 弃权
  • ACCESS_DENIED -1反对票
  • ACCESS_GRANTED 1通过票

一次只能使用一个决策器,可以使用多个投票器。
来看决策器的源码
AffirmativeBased.java

public void decide(Authentication authentication, Object object,
			Collection<ConfigAttribute> configAttributes) throws AccessDeniedException {
		int deny = 0;
		//循环配置的所有投票器
		for (AccessDecisionVoter voter : getDecisionVoters()) {
			int result = voter.vote(authentication, object, configAttributes);

			if (logger.isDebugEnabled()) {
				logger.debug("Voter: " + voter + ", returned: " + result);
			}
			//此处逻辑可以看出,只要有一票通过则通过
			switch (result) {
			case AccessDecisionVoter.ACCESS_GRANTED:
				return;

			case AccessDecisionVoter.ACCESS_DENIED:
				deny++;

				break;

			default:
				break;
			}
		}

		if (deny > 0) {
			throw new AccessDeniedException(messages.getMessage(
					"AbstractAccessDecisionManager.accessDenied", "Access is denied"));
		}
		//如果所有都弃权了怎么办?在父类里面有个属性allowIfAllAbstainDecisions 配置为true 则算通过,如果为false 则不通过抛出拒绝访问异常。默认false
		// To get this far, every AccessDecisionVoter abstained
		checkAllowIfAllAbstainDecisions();
	}

同理其它的决策器也是如此不多介绍。

那么如果不用默认配置,我们应该如何配置它呢?你只需要自定义AccessDecisionManager的实例化过程即可。如下配置了默认RoleVoter以及自定义Voter。然后将accessDecisionManager 配置给 http即可。

    @Bean
    public AccessDecisionManager accessDecisionManager(){
        //此处无需用linkList 本身与顺序无关。
        List<AccessDecisionVoter<? extends Object>> decisionVoters=new ArrayList<>();
        AccessDecisionVoter roleVoter=new RoleVoter();
        decisionVoters.add(roleVoter);
        decisionVoters.add(customVoter);
        return new AffirmativeBased(decisionVoters);
    }
//代码片段其它内容自己加
public void configure(HttpSecurity http){
		 http.authorizeRequests().accessDecisionManager(accessDecisionManager());
}

也就是说,如果我们需要扩展,直接实现一个voter,然后将之注册到AccessDecisionManager中即可。

AbstractInterceptUrlConfigurer.getAccessDecisionManager中可以看到,security默认配置的就是AffirmativeBased 决策器

/**
	 * Creates the default {@code AccessDecisionManager}
	 * @return the default {@code AccessDecisionManager}
	 */
	private AccessDecisionManager createDefaultAccessDecisionManager(H http) {
		AffirmativeBased result = new AffirmativeBased(getDecisionVoters(http));
		return postProcess(result);
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值