【微服务|Spring Security⑭】spring security授权流程

Spring Security可以通过http.authorizeRequests()对web请求进行授权保护。Spring Security使用标准Filter建立了对web请求的拦截,最终实现对资源的授权访问。

Spring Security的授权流程如下:

在这里插入图片描述

分析授权流程:

1.拦截请求,已认证用户访问受保护的web资源将被SecurityFilterChain中的FiltersecurityInterceptor的子类拦截。

2.获取资源访问策略,FilterSecurityInterceptor会从 SecurityMetadataSource 的子类 DefaultFilterlnvocationSecurityMetadataSource获取要访问当前资源所需要的权限Collection<ConfigAttribute> 。

SecurityMetadataSource其实就是读取访问策略的抽象,而读取的内容,其实就是我们配置的访问规则,读取访问策略如:

http
	.authorizeRequests() 
		.antMatchers("/r/r1").hasAuthority("p1")
		.antMatchers("/r/r2").hasAuthority( "p2")

3.Filtersecurityinterceptor会调用AccessDecisionManager进行授权决策,若决策通过,则允许访问资源,否则将禁止访问。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.access;

import java.util.Collection;
import org.springframework.security.authentication.InsufficientAuthenticationException;
import org.springframework.security.core.Authentication;

public interface AccessDecisionManager {
    
    
	/**
	*通过传递的参数来决定用户是否有访问对应受保护资源的权限
	*/
    void decide(Authentication var1, Object var2, Collection<ConfigAttribute> var3) throws AccessDeniedException, InsufficientAuthenticationException;

    boolean supports(ConfigAttribute var1);

    boolean supports(Class<?> var1);
}

这里着重说明一下decide的参数:

authentication :要访问资源的访问者的身份

object :要访问的受保护资源,web请求对应Fi足revocation

configAttributes :是受保护资源的访问策略,通过SecurityMetadataSource获取。

decide接口就是用来鉴定当前用户是否有访问对应受保护资源的权限。

授权决策

AccessDecisionManager采用投票的方式来确定是否能够访问受保护资源。

AccessDecisionManager中包含的一系列AccessDecisionVoter将会被用来对Authentication是否有权访问受保护对象进行投票,AccessDecisionManager根据投票结果,做出最终决策。

AccessDecisionVoter是一个接口 ,其中定义有三个方法,具体结构如下所示。

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package org.springframework.security.access;

import java.util.Collection;
import org.springframework.security.core.Authentication;

public interface AccessDecisionVoter<S> {
    
    
    int ACCESS_GRANTED = 1;
    int ACCESS_ABSTAIN = 0;
    int ACCESS_DENIED = -1;

    boolean supports(ConfigAttribute var1);

    boolean supports(Class<?> var1);

    int vote(Authentication var1, S var2, Collection<ConfigAttribute> var3);
}

vote()方法的返回结果会是AccessDecisionVoter中定义的三个常量之一。

  • ACCESS_GRANTED表示同意
  • ACCESS_DENIED表示拒绝
  • ACCESS_ABS7AIN表示弃权

如果一个AccessDecisionVoter不能判定当前 Authentication是否拥有访问对应受保护对象的权限,则其vote()方法的返回值应当为弃权ACCESS_ABSTAIN。

Spring Security内置了三个基于投票的AccessDecisionManager实现类,它们分别是
AffirmativeBased、ConsensusBased和UnanimousBased。

AffirmativeBased的逻辑是:

  • 只要有AccessDecisionVoter的投票为ACCESS_GRANTED则同意用户进行访问;
  • 如果全部弃权也表示鮑;
  • 如果没有一个人投赞成票,但是有人投反对票,则将抛出AccessDeniedException, Spring security默认使用的是AffirmativeBased。

ConsensusBased的逻辑是:

  • 如果赞成票多于反对票则表示通过。
  • 反过来,如果反对票多于赞成票则将抛出AccessDeniedException,
  • 如果赞成票与反对票相同且不等于0 ,并且属性allowlfEqualGrantedDeniedDecisions的值为true,则表示通过,否则将抛出异常AccessDeniedException。参数allowlfEqualGrantedDeniedDecisions的值默认为true。
  • 如果所有的AccessDecisionVoter都弃权了,则将视参数allowlfAIIAbstainDecisions的值而定,如果该值为true则表示通过,否则将抛出异常AccessDeniedExceptiono。参数allowlfAIIAbstainDecisions的值默认为false。

UnanimousBased

UnanimousBased的逻辑与另外两种实现有点不一样,另外两种会一次性把受保护对象的配置属性全部传递给AccessDecisionVoter进行投票,而UnanimousBased会一次只传递一个ConfigAttribute给AccessDecisionVoter进行投票。这也就意味着如果我们的AccessDecisionVoter的逻辑是只要传递进来的ConfigAttribute中有一个能够匹配则投赞成票,但是放到UnanimousBased中其投票结果就不一定是赞成了。

UnanimousBased的逻辑具体来说是这样的:

  • 如果受保护对象配置的某一个ConfigAttribute被任意的AccessDecisionVoter反对了,则将抛出 AccessDeniedExceptiono
  • 如果没有反对票,但是有赞成票,则表示通过。
  • 如果全部弃权了,则将视参数allowlfAIIAbstainDecisions的值而定,true则通过,false则抛出 AccessDeniedExceptiono SpringSecurity也内置一些投票者实现类如RoleVoter、AuthenticatedVoter和WebExpressionVoter等,可以自行查阅资料进行学习。

猜你喜欢

转载自blog.csdn.net/CSDN_SAVIOR/article/details/125683317