SpringSecurity(二)

谁说我不能喝 提交于 2021-01-02 14:02:23

### 文章目录

[toc]

# 一、授权流程

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

 `Spring Security`的授权流程如下:

![](https://img-blog.csdnimg.cn/20200406235818944.png)
分析授权流程:

1. **拦截请求**,已认证用户访问受保护的 `web`资源被 `SpringFilterChain`中的 `FilterSecurityInterceptor`的子类拦截。

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

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

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

```

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

## 1.1 AccessDecisionManager

`AccessDecisionManager`接口定义:

```java
public interface AccessDecisionManager {
    void decide(Authentication var1, Object var2,
        Collection<ConfigAttribute> var3)
        throws AccessDeniedException,
        InsufficientAuthenticationException;
    boolean supports(ConfigAttribute var1);
    boolean supports(Class<?> var1);
}
```

 `decide()`方法是 `AccessDecisionManager`的核心, **用来鉴定当前用户是否有访问对应受保护资源的权限**,其中参数:

 `var1`:要访问资源的访问者的身份

 `var2`:要访问的受保护资源,web请求对应 `FilterInvocation`

 `var3`:是受保护资源的访问策略,通过 `SecurityMetadatasource`

## 1.2 授权决策

`AccessDecisionManager`采用投票的方式来确定是否能够访问受保护资源。
![](https://img-blog.csdnimg.cn/20200407224236206.png)
通过上图可以看出, `AccessDecisionManager`中包含了一系列 `AccessDecisionVoter`将会被用来对 `Authentication`是否有权访问受保护对象进行投票, `AccessDecisionManager`根据投票结果,做出最终决策。

 `AccessDecisionVoter`接口定义如下:

```java
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_ABSTAIN`表示弃权。如果 `AccessDecisionVoter`不能判定当前 `Authentication`是否拥有访问对应受保护对象的权限,则 `vote()`方法的返回值为 `ACCESS_ABSTAIN` 。

 `Spring Security`内置了三个基于投票的 `AccessDecisionManager`实现类如下,它们分别是 `AffirmativeBased`、 `ConsensusBased`和 `UnaimousBased`。 `Spring Security`默认使用的是 `AffirmativeBased`。

**​1、AffirmativeBased:**

 ①只要有 `AccessDecisionVoter`的投票为 `ACCESS_GRANTED`则同意用户进行访问;

 ②如果全部弃权也表示通过;

 ③如果没有一个投赞成票,但是有人投反对票,则将抛出 `AccessDeniedException`。

**​2、ConsensusBased:**

 ①如果赞成票多余反对票则表示通过;

 ②如果反对票多于赞成票则将抛出 `AccessDeniedException`。

 ③如果赞成票与反对票相同且不等于0,并且属性 `allowEqualGrantedDeniedDecision`的值为true,则表示通过,否则将抛出 `AccessDeniedException`。 `allowEqualGrantedDeniedDecision`的默认值为true。

 ④如果所有的 `AccessDecisionVoter`都弃权了,则将视参数 `allowIfAllAbstainDecisions`的值而定,如果该值为true则表示通过,否则将抛出异常 `AccessDeniedException`。参数 `allowIfAllAbstainDecisions`的值默认为false。

**3、UnanimousBased:**

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

 ②如果没有反对票,但是有赞成票,则表示通过。

 ③如果全部弃权了,则将视参数 `allowIfAllAbstainDecisions`的值而定,true则通过,false则抛出 `AccessDeniedException`。

`Spring Security`也内置一些投票者实现类如 `RoleVoter`、 `AuthenticatedVoter`和 `WebExpressionVoter`等。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!