web-dev-qa-db-ja.com

Spring Security OAuth-プロバイダーマネージャーがnullリソース用に構成されていません

Spring SecruityのOAuth APIを使用して、外部公開APIからアクセストークンを取得しようとしています。

このcurlコマンドは機能します(その内容は、アクセストークンを取得するために必要なすべてです):

curl -X POST \
https://api.app.com/v1/oauth/token \
  -H 'content-type: application/x-www-form-urlencoded' \
  -d'grant_type=client_credentials&client_id=bcfrtew123&client_secret=Y67493012'

このcurlコマンドを実行した後、外部サービスからアクセストークンを取得できます。

Spring Securityを使用する場合OAuth API:

<dependency>
   <groupId>org.springframework.security.oauth</groupId>
     <artifactId>spring-security-oauth2</artifactId>
     <version>2.1.1.RELEASE</version>
</dependency>

SpringMVCコントローラーのメソッドを次のように設定します。

@RequestMapping(value = "/getAccessToken", method = RequestMethod.POST, consumes="application/x-www-form-urlencoded")
public OAuth2AccessToken getAccessToken(@RequestParam(value="client_id", required=true) String clientId, @RequestParam(value="client_secret", required=true) String clientSecret) throws Exception {
    String tokenUri = "https://api.app.com/v1/oauth/token";

    ResourceOwnerPasswordResourceDetails resourceDetails = new ResourceOwnerPasswordResourceDetails();

    resourceDetails.setAccessTokenUri(tokenUri);
    resourceDetails.setClientId(clientId);
    resourceDetails.setClientSecret(clientSecret);
    resourceDetails.setGrantType("client_credentials");
    resourceDetails.setScope(Arrays.asList("read", "write"));

    DefaultOAuth2ClientContext clientContext = new DefaultOAuth2ClientContext();

    oauth2RestTemplate = new OAuth2RestTemplate(resourceDetails, clientContext);

    OAuth2AccessToken token = oauth2RestTemplate.getAccessToken();
    return token;
}

ローカルのTomcatインスタンスからgetAccessToken呼び出しを呼び出すと、次のようになります。

access_denied 
error_description=Unable to obtain a new access token for resource 'null'. 
The provider manager is not configured to support it.

質問:

  1. ここで何が欠けていますか?これにはいくつかの注釈が必要ですか?設定されていない、または必要なプロパティはありますか?

(content-typeは "application/x-www-form-urlencoded"である必要があることに注意してください...)

  1. Spring Security OAuth APIを使用して、有効なcurlコマンドを模倣するにはどうすればよいですか?

  2. これは、RequestParametersで設定したデフォルト値ですか?

  3. 成功した場合、リクエストを行う前にアクセストークンが常にプリロードされるように設定するにはどうすればよいですか?

12
PacificNW_Lover

実際の理由は、"client_credentials"アクセストークンリクエストにResourceOwnerPasswordResourceDetailsを使用しているためです。 ResourceOwnerPasswordResourceDetailsClientCredentialsResourceDetailsを入れ替えることはできません。

ClientCredentialsResourceDetailsでは、AccessTokenUri, ClientId, ClientSecretgrantTypeを設定する必要があります。 ResourceOwnerPasswordResourceDetailsでは、Username and PasswordAccessTokenUri, ClientId, ClientSecretおよびGrantTypeを提供する必要があります。

(一部の認証サーバーはusername and passwordなしでpasswordトークン要求を受け入れます。しかし、私はそれが間違っていると思います)

参照: 既存のAPIを独自のソリューションで保護する

3
Abbin Varghese

これは私が使用するものです:

_@Bean
public RestTemplate oAuthRestTemplate() {
    ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
    resourceDetails.setId("1");
    resourceDetails.setClientId(oAuth2ClientId);
    resourceDetails.setClientSecret(oAuth2ClientSecret);
    resourceDetails.setAccessTokenUri(accessTokenUri);

    OAuth2RestTemplate restTemplate = new OAuth2RestTemplate(resourceDetails, oauth2ClientContext);

    return restTemplate;
}
_

正しいヘッダーはフレームワークによって設定されますが、ユーザー名/パスワードはAuthorizationヘッダー(基本認証)としてbase64エンコードされます。これはclient_credentials付与のOAuth2仕様です。

APIが仕様をサポートしているかどうかを確認します。

_curl -X POST \
'https://api.app.com/v1/oauth/token' \
-i -u 'client:secret' \
-H 'Content-Type: application/x-www-form-urlencoded' \
-d 'grant_type=client_credentials'
_

ユーザー名とパスワードを認証ヘッダーではなくデータとして送信する必要がある場合は、resourceDetails.setAuthenticationScheme(AuthenticationScheme.form);を追加できます。これにより、ユーザー名とパスワードがデータとして設定されます。

2
JohanB

サーバーがその特定のURLに投稿したコンテンツタイプを認識しないため、これが発生する可能性があります。 CURLリクエストに、httpヘッダーを使用するカスタムコントローラーの「content-type:application/x-www-form-urlencoded」を含めてみてください。 Http headers

また、resourceDetailsのユーザー名とパスワードを設定していません。 resourceDetails.setUserName( "user"); resourceDetails.setUserName( "password");

これらが機能しない場合は、application/x-www-form-urlencodedでエンコードされたリクエストを抽出し、RestTemplateを介して文字列として渡して、トークンを取得できます。

追加のサポートが必要な場合はお知らせください。

トークンとして文字列応答を返す以下のコードを試してください。

enter image description here

0