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等,可以自行查阅资料进行学习。
原文始发于微信公众号(步尔斯特):【微服务|Spring Security⑭】spring security授权流程
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/48005.html