Spring Security OAuth 之 @EnableResourceServer 干了啥?

1,790 阅读3分钟

这是我参与2022首次更文挑战的第8天,活动详情查看:2022首次更文挑战

上一篇(《Spring Security OAuth 之 @EnableAuthorizationServer 干了啥? 》)试着分析了 @EnableAuthorizationServer 注解是如何完成授权服务器的配置的,这篇来分析 @EnableResourceServer 是如何完成资源服务器配置的。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import(ResourceServerConfiguration.class)
public @interface EnableResourceServer {

}

EnableResourceServer 中,通过 @``Import 注解,导入了 ResourceServerConfiguration 配置类。我们找到它的源码,然后把关键部分拿出来分析:

@Override
protected void configure(HttpSecurity http) throws Exception {
   ResourceServerSecurityConfigurer resources = new ResourceServerSecurityConfigurer();

   /* 省略部分代码 */

   http.apply(resources);
   
   /* 省略部分代码 */
}

以上的源码中,省略了两部分,第一部分在配置和应用一个 ResourceServerSecurityConfigurer 类型的配置对象,这是这个配置方法中最主要的部分,第二个省略的部分并不是重点。因此我们找到 ResourceServerSecurityConfigurer 类型的源码,分析其中的配置内容:

@Override
public void configure(HttpSecurity http) throws Exception {

   AuthenticationManager oauthAuthenticationManager = oauthAuthenticationManager(http);
   resourcesServerFilter = new OAuth2AuthenticationProcessingFilter();
   resourcesServerFilter.setAuthenticationEntryPoint(authenticationEntryPoint);
   resourcesServerFilter.setAuthenticationManager(oauthAuthenticationManager);
   if (eventPublisher != null) {
      resourcesServerFilter.setAuthenticationEventPublisher(eventPublisher);
   }
   if (tokenExtractor != null) {
      resourcesServerFilter.setTokenExtractor(tokenExtractor);
   }
   if (authenticationDetailsSource != null) {
      resourcesServerFilter.setAuthenticationDetailsSource(authenticationDetailsSource);
   }
   resourcesServerFilter = postProcess(resourcesServerFilter);
   resourcesServerFilter.setStateless(stateless);
   // @formatter:off
   http
      .authorizeRequests().expressionHandler(expressionHandler)
   .and()
      .addFilterBefore(resourcesServerFilter, AbstractPreAuthenticatedProcessingFilter.class)
      .exceptionHandling()
         .accessDeniedHandler(accessDeniedHandler)
         .authenticationEntryPoint(authenticationEntryPoint);
   // @formatter:on
}

private AuthenticationManager oauthAuthenticationManager(HttpSecurity http) {
   OAuth2AuthenticationManager oauthAuthenticationManager = new OAuth2AuthenticationManager();
   if (authenticationManager != null) {
      if (authenticationManager instanceof OAuth2AuthenticationManager) {
         oauthAuthenticationManager = (OAuth2AuthenticationManager) authenticationManager;
      }
      else {
         return authenticationManager;
      }
   }
   oauthAuthenticationManager.setResourceId(resourceId);
   oauthAuthenticationManager.setTokenServices(resourceTokenServices(http));
   oauthAuthenticationManager.setClientDetailsService(clientDetails());
   return oauthAuthenticationManager;
}

我们分析其中的内容:

  • 代码第 4 行,方法开头,通过 oauthAuthenticationManager 方法,创建了一个 AuthenticationManager 对象,从源码中可以看到,这个对象的实现类型是 OAuth2AuthenticationManager
  • 代码第 5 行到第 18 行,创建并配置了 OAuth2AuthenticationProcessingFilter 作为处理资源服务器认证流程的过滤器,上一步骤中创建的 AuthenticationManager 也会被配置给这个过滤器。并将这个过滤器添加到过滤器链上。

这篇源码分析到此为止,已经分析出了 @EnableResourceServer 注解所做的事情,其实就是在 Spring Security 的过滤器链里,增加了一个过滤器,对客户端对资源的访问请求进行拦截,然后校验其合法性。具体的认证过程,可以参考我的另一篇分析 Spring Security OAuth 资源服务器认证

这里要顺便还要提两点:

  1. 之前的文章(Spring Security 认证流程 )中分析过的 ProviderManager 类型,也是 AuthenticationManager 接口的实现类,通过 authentication 方法完成用户信息认证。因此,这里的 OAuth2AuthenticationManager 与其作用和原理相似。找到它们的共同点,有助于你理解其原理。
  2. 之前的另一篇文章(Spring Security OAuth 资源服务器认证 )曾提到了,资源服务器的过滤器OAuth2AuthenticationProcessingFilter 使用的 authenticationManager 类型是 OAuth2AuthenticationManager,当时没有解释为什么是这个类,其实,它就是在这里配置的。想要了解资源服务器认证的具体过程,也可以去参考这篇文章。

这篇内容比较少,但是提到了一些与其他文章相重合或者相关联的地方,感兴趣的话,可以都读一读,可以帮助你完善自己的理解。