【问题标题】:Microservices and Spring Security OAuth2微服务和 Spring Security OAuth2
【发布时间】:2014-12-27 11:34:21
【问题描述】:

我已经在另一个项目中运行了 OAuth2 授权服务器。现在我需要使用 OAuth2 保护几个简单的 spring-boot 休息服务器。但我发现 Spring documentation 在分离授权和资源服务器方面确实非常有限。

我还发现了几个问题,the answer 一直是“只要它们共享相同的 tokenStore 数据源,它们就可以是不同的盒子”。这真的是真的吗?这怎么可能适用于微服务?每个 REST 服务都需要实现自己的 OAuth 授权服务器,这似乎是一件非常奇怪的事情。

那么,如何为引用远程 oauth 授权服务器(甚至可能不是用 Spring 编写)的 spring-boot rest-endpoints 设置 Oauth2.0 安全性?

有一个叫做RemoteTokenServices 的东西看起来很有希望,但它根本没有真正记录在案。

【问题讨论】:

    标签: spring spring-security oauth-2.0


    【解决方案1】:

    RemoteTokenService 的工作示例可以在 here 找到。

    更多关于check_tokenapi的详细信息,可以参考org.springframework.security.oauth2.provider.endpoint.CheckTokenEndpoint.java

    在资源服务器端,OAuth2AuthenticationProcessingFilter 通过调用 OAuth2AuthenticationManager.authenticate() 方法验证 OAuth2 令牌,该方法调用 RemoteTokenServices.loadAuthentication() 以验证来自 Auth 服务器的令牌。

    【讨论】:

      【解决方案2】:

      在配置您的 auh 服务器时::

      ClientDetailsServiceConfigurer 中为资源服务器创建一个新的clientDetails。将用于配置RemoteTokenService

      在资源服务器中配置 Spring Security OAuth2:

      创建一个使用@EnableWebSecurity@Configuration 注释并扩展WebSecurityConfigurerAdapter 的类。

      @Configuration
      @EnableWebSecurity
      protected static class ResourceConfiguration extends WebSecurityConfigurerAdapter {
        // methods        
      }
      

      创建一个带有@Bean 注解的方法,该方法将返回TokenService 的实例,该实例将用于创建AuthenticationManager

      在这个方法中创建一个RemoteTokenService的实例并设置clientId、client_secret、checkTokenEndpointUrl和DefaultAccessTokenConverterWithClientRoles(这个类是我们在验证accessToken时获取client_authority的实现在 OAuth2 服务器中。)

      @Bean
      public ResourceServerTokenServices tokenService() {
          RemoteTokenServices tokenServices = new RemoteTokenServices();
          tokenServices.setClientId("resource_id");
          tokenServices.setClientSecret("resource_secret");
          tokenServices.setCheckTokenEndpointUrl("http://<server-url>: <port>/oauth/check_token");
          return tokenServices;
      }
      

      覆盖authenticationManagerBean() 方法并使用@Bean 对其进行注释,并返回一个OAuth2AuthenticationManager 的实例并注入TokenService

      @Override
      @Bean
      public AuthenticationManager authenticationManagerBean() throws Exception {
          OAuth2AuthenticationManager authenticationManager = new OAuth2AuthenticationManager();
          authenticationManager.setTokenServices(tokenService());
          return authenticationManager;
      }
      

      创建一个用@EnableResourceServer@Configuration注解的类并扩展ResourceServerConfigurerAdapter

      @Configuration
      @EnableResourceServer
      protected static class ResourceServerConfig extends ResourceServerConfigurerAdapter {
        // Mehotds
      }
      

      覆盖超类的配置方法来配置资源服务器。 不同的配置器来配置资源服务器。

      ResourceServerSecurityConfigurer:配置Resource_id。

      HttpSecurity:这将配置安全过滤器,告诉它用户需要对受保护的 URL (API) 进行身份验证。

      @Override
      public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          resources.resourceId("resource_id");
      }
      
      @Override
      public void configure(HttpSecurity http) throws Exception {
          // @formatter:off
          http
           .authorizeRequests()
           .antMatchers("/**").authenticated()
           .and()
           .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
          // @formatter:on
      }
      

      .antMatcher("/**").authenticated() 这一行将保护资源服务器的每个 api url。 .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) 不会创建会话。

      PS:: 如果有什么不对的,请告诉我。

      【讨论】:

      • 此设置是否在真实应用中测试过?其中大部分看起来与我在项目中所做的相同。但是,我在无状态配置方面遇到了麻烦。登录和授权页面之间丢失了一些东西。我认为 OAuth2 实现不支持无状态设置,因为 RequestCache 接口的唯一实现需要一个 http 会话来存储请求信息(HttpSessionRequestCache)。无状态策略会将此请求数据存储回响应中(可能在 cookie 中),因此任何其他副本都可以继续授权
      【解决方案3】:

      如果资源服务器有某种方法可以验证访问令牌是否真实(由授权服务器颁发)以及某种解码方法(可能需要例如,了解它授予的范围)。 OAuth2 规范没有说明如何实现这一点。

      如果资源与授权服务器在同一个进程中,那么共享数据是一个简单的选择。否则,它需要某种方式来翻译令牌。如果令牌只是一个不透明的随机字节串,那么显然它必须用它来交换真实的信息。这就是RemoteTokenServices 所做的。授权服务器公开一个/check_token 端点以允许对令牌进行解码。

      另一种方法是对令牌中的信息进行实际编码,并让授权服务器对其进行数字签名。然后资源服务器可以解码和验证令牌本身,只要它理解格式。

      我建议您查看 Cloudfoundry UAA,它提供了一个开箱即用的授权服务器,该服务器使用签名的 JWT 令牌实现(它还公开了 /check_token 端点)。 Tokens overviewAPI docs 可能是一个很好的起点。

      【讨论】:

      • tokenServices.setCheckTokenEndpointUrl("http://&lt;server-url&gt;: &lt;port&gt;/oauth/check_token"); 有没有办法避免硬编码的网址?我想直接调用任何一个身份验证服务器实例(从注册表服务器获取运行时 url)或从 redis 检查令牌。 (在 auth 中使用 redis 令牌存储)这有可能吗?
      猜你喜欢
      • 2017-02-03
      • 2013-10-18
      • 2017-03-31
      • 2015-05-22
      • 2013-12-21
      • 2018-07-08
      • 1970-01-01
      • 2019-11-27
      • 2015-03-11
      相关资源
      最近更新 更多