Authorization in Spring Security(1)

1. 根据什么数据进行授权

认证成功后以 GrantedAuthority 的形式保存在 Authentication 对象中的 authorities 会别用来进行授权运算。

请求被 AuthenticationManager 认证之后,其 Principal 的 authorities 以一组 GrantedAuthority 的形式被保存在 Authentication 对象里。

public interface GrantedAuthority extends Serializable {
    String getAuthority();
}

在是否可以对 security object (比如一个方法的调用、一个 web request 的处理)进行访问之前,需要使用 AuthorizationManager 来决定是否可以 invoke 这些 security objects。
如果这些授权不能以 String 的形式表达出来,那么就用返回 null 的形式告诉 AuthorizationManager/AccessDecisionManager 需要自己进行特殊的处理。 Spring Security 源码里就有一个这样的例子,请参阅: WebExpressionConfigAttribute, WebExpressionVoter。

2. 通过 AuthorizationManager 体会设计的改进

AuthorizationManager 是在 spring security 5.5 中被加入。从 spring-security-core-6.0 开始,AccessDecisionManager AccessDecisionVoter 已经被 deprecated,由 AuthorizationManager 取代其作用。 对于之前定制化 AccessDecisionManager AccessDecisionVoter 的代码应该考虑迁移到 AuthorizationManager。

AuthorizationManager
AuthorizationManager

AccessDecisionManager
AccessDecisionManager

AccessDecisionVoter
AccessDecisionVoter

  1. 之前 AccessDecisionManager 通过抛出异常,现在 default 的 verify 也是通过 exception。
  2. 明确返回 AuthorizationDecision 来标识。
  3. 之前有 support 方法,跟 AuthenticationProvider 的思路很像。
    从方法签名可以直接看出上面这几点。官方文档列出了更有意义的变化:
  4. AuthorizationManager 的 API 相对于之前 FilterSecurityInterCepter/AccessDecisionManager 要使用 metadata sources, config attributes, decison managers, voters 进行授权判断要简化很多。
  5. 因为通过把 AuthenticationManger 放在 Supplier 中实现了对认证数据的延迟访问,这对一些无需认证的授权是有好处的。
  6. 支持基于 Bean 的配置。

3. AuthorizationManagers/AuthorizationFilter 以及 AccessDecisionManager/FilterSecurityInterceptor

AuthorizationManagers 被 AuthorizationFilter 来使用,负责做出是否允许访问的决定。
为了保证向后兼容,FilterSecurityInterceptor 作为用于授权的 security fitler 依旧是默认的 Spring Security Filters 之一,在倒数第二的位置上。

... ...
SessionManagementFilter
ExceptionTranslationFilter
FilterSecurityInterceptor
SwitchUserFilter

4. 如何在 Security Filters 中使用 AuthorizationFilter 或 FilterSecurityInterceptor?

在通过 HttpSecurity 构建 SecurityFilterChain 的时候调用authorizeHttpRequests() 就会在 security fitler chain 中插入AuthorizationFilter,而调用****authorizeRequests()****则会插入 security filter FilterSecurityInterceptor

@Bean
SecurityFilterChain web(HttpSecurity http) throws AuthenticationException {
    http
        .authorizeHttpRequests((authorize) -> authorize
            .anyRequest().authenticated();
        )
        // ...

    return http.build();
}

5. 详细的使用范式

关于 AuthorizationFilter/AuthorizationManger,可参考:https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-http-requests.html

关于 FilterSecurityInterceptor,可参考: https://docs.spring.io/spring-security/reference/servlet/authorization/authorize-requests.html



References:
[1]: https://docs.spring.io/spring-security/reference/servlet/authorization/index.html