为什么我的令牌被拒绝?什么是资源 ID? “无效令牌不包含资源 ID (oauth2-resource)”

新手上路,请多包涵

我正在尝试为 spring 项目配置 OAuth2。我正在使用我的工作场所提供的共享 UAA( 来自 cloud foundry 的 oauth 实现)实例(因此我没有尝试创建授权服务器,并且授权服务器与资源服务器是分开的)。前端是一个单页应用程序,它使用隐式授权直接从授权服务器获取令牌。我有 SPA 设置,它在每个对微服务的 Web API 调用上添加了 Authorization: Bearer <TOKEN> 标头。

我现在的问题是微服务。

我正在尝试使用此共享授权服务器来验证微服务。我在这里可能有一个误解,买我目前的理解是这些微服务扮演资源服务器的角色,因为它们托管 SPA 用来获取数据的端点。

所以我尝试像这样配置微服务:

 @Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.csrf().disable()
        .authorizeRequests()
        .antMatchers("/api/**").authenticated();
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setVerifierKey("-----BEGIN PUBLIC KEY-----<key omitted>-----END PUBLIC KEY-----");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
         resources.tokenServices(tokenServices());
    }
}

现在,每当我用 /api/** Authorization: Bearer <TOKEN> 时,我都会得到 403 并出现此错误:

 {
    "error": "access_denied",
    "error_description": "Invalid token does not contain resource id (oauth2-resource)"
}


所以这是我的问题:

  • 如何配置这些微服务以验证令牌并在控制器方法中插入 Principal 我目前在 SPA 拥有并发送令牌的地方设置它,我还有用于验证令牌签名的公钥。我还使用 jwt.io 来测试令牌,它显示“签名已验证”。
  • 什么是资源ID?为什么我需要它,为什么会导致上面的错误?那是春天唯一的事情吗?

谢谢!

原文由 Rico Kahler 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 764
2 个回答

Spring OAuth 期望 JWT 令牌中的“aud” 声明。该声明的值应与您指定 Spring 应用程序的 resourceId 值匹配(如果未指定,则默认为“oauth2-resource”)。

要解决您的问题,您需要:

  1. 登录您的共享 UAA 并确保它包含“aud”声明。

  2. 将该“aud”声明的值更改为“oauth2-resource”,或者最好在您的 Spring 应用程序更新中 resourceId 更改为该声明的值,如下所示:

     @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
         resources.tokenServices(tokenServices());
         resources.resourceId(value from the aud claim you got from UAA server);
    }

原文由 tsolakp 发布,翻译遵循 CC BY-SA 3.0 许可协议

我补充一个类似的问题。就我而言,我使用了 jdbc 身份验证,我的授权服务器和资源服务器是两个独立的 API。

  • 授权服务器
     @Override
  public void configure(AuthorizationServerSecurityConfigurer oauthServer) {
  oauthServer.tokenKeyAccess("permitAll()")
              .checkTokenAccess("isAuthenticated()")
              .passwordEncoder(oauthClientPasswordEncoder);

}

   /**
  * Define the client details service. The client may be define either as in memory or in database.
   * Here client with be fetch from the specify database
    */
  @Override
  public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
     clients.jdbc(dataSource);
  }

  /**
  * Define the authorization by providing authentificationManager
  * And the token enhancement
   */
   @Override
  public void configure(AuthorizationServerEndpointsConfigurer endpoints) {
  endpoints.tokenStore(tokenStore())
              .tokenEnhancer(getTokenEnhancer())
              .authenticationManager(authenticationManager).userDetailsService(userDetailsService);
   }

  • 资源服务器
  public class OAuth2ResourceServerConfig extends
      ResourceServerConfigurerAdapter {

      private TokenExtractor tokenExtractor = new BearerTokenExtractor();

      @Autowired
      private DataSource dataSource;

      @Bean
      public TokenStore tokenStore() {
        return new JdbcTokenStore(dataSource);
      }

       @Override
       public void configure(HttpSecurity http) throws Exception {
             http.addFilterAfter(new OncePerRequestFilter() {
             @Override
             protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
              FilterChain filterChain) throws ServletException, IOException {
          // We don't want to allow access to a resource with no token so clear
          // the security context in case it is actually an OAuth2Authentication
          if (tokenExtractor.extract(request) == null) {
              SecurityContextHolder.clearContext();
          }
          filterChain.doFilter(request, response);
      }
  }, AbstractPreAuthenticatedProcessingFilter.class);
  http.csrf().disable();
  http.authorizeRequests().anyRequest().authenticated();
   }

    @Bean
    public AccessTokenConverter accessTokenConverter() {
       return new DefaultAccessTokenConverter();
    }

    @Bean
    public RemoteTokenServices remoteTokenServices(final @Value("${auth.server.url}") String checkTokenUrl,
      final @Value("${auth.resource.server.clientId}") String clientId,
      final @Value("${auth.resource.server.clientsecret}") String clientSecret) {

         final RemoteTokenServices remoteTokenServices = new RemoteTokenServices();
         remoteTokenServices.setCheckTokenEndpointUrl(checkTokenUrl);
         remoteTokenServices.setClientId(clientId);
         remoteTokenServices.setClientSecret(clientSecret);
        remoteTokenServices.setAccessTokenConverter(accessTokenConverter());
  return remoteTokenServices;
     }

通过这种配置,我得到了

    {
       "error": "access_denied",
       "error_description": "Invalid token does not contain resource id
       (xxxxx)"
     }

为了解决这个问题,我不得不添加

    private String resourceIds= "xxxxx". !! maked sure that this resourceids is store in oauth_client_details for the clientid I used to get the token
    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
          resources.resourceId(resourceIds).tokenStore(tokenStore());
      }

原文由 onlyme 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
logo
Stack Overflow 翻译
子站问答
访问
宣传栏