web-dev-qa-db-ja.com

トークンが拒否されるのはなぜですか?リソースIDとは何ですか? 「無効なトークンにリソースID(oauth2-resource)が含まれていません」

春のプロジェクト用にOAuth2を設定しようとしています。共有UAA( クラウドファウンドリからのoauth実装 )インスタンスを使用しています(したがって、承認サーバーを作成しようとしておらず、承認サーバーはリソースサーバーとは別です)。フロントエンドは単一ページのアプリケーションであり、暗黙的な許可を使用して認可サーバーから直接トークンを取得します。マイクロサービスへの各Web API呼び出しにAuthorization: Bearer <TOKEN>ヘッダーを追加するSPAセットアップがあります。

私の問題はマイクロサービスにあります。

この共有認証サーバーを使用して、マイクロサービスを認証しようとしています。ここで誤解があるかもしれませんが、これらのマイクロサービスは、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 を使用しましたが、「Signature Verified」と表示されます。
  • リソースIDとは何ですか?なぜ必要なのか、なぜ上記のエラーが発生するのですか?それは春だけですか?

ありがとう!

12
Rico Kahler

Spring OAuthは、「aud」を期待します claim JWTトークン。そのクレームの値は、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);
    }
24
tsolakp

同様の問題を追加します。私の場合、jdbc認証を使用し、承認サーバーとリソースサーバーは2つの別個の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());
      }
2
onlyme