我试图使用Spring Secruity的OAuth API从基于Spring MVC 4的Web服务(而不是Spring Boot)中的外部发布的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'
Spring Security OAuth API:
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
<version>2.1.1.RELEASE</version>
</dependency>
我获取访问令牌的代码:
@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.
我怀疑原因是我的Http Header的Content-Type没有设置
application/x-www-form-urlencoded
我该如何设置:
import org.springframework.security.oauth2.client.OAuth2RestTemplate;
如果您注意到,我试图在@RequestMapping内部进行设置并且不认为它的工作原理:
@RequestMapping(consumes="application/x-www-form-urlencoded")
在客户端凭据的情况下,用于访问Oauth2Restemplate中的令牌的http标头在ClientCredentialsAccessTokenProvider的以下方法中设置(因为授权类型是客户端凭据)
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
throws UserRedirectRequiredException, AccessDeniedException,
OAuth2AccessDeniedException {
ClientCredentialsResourceDetails resource = (ClientCredentialsResourceDetails) details;
return retrieveToken(request, resource, getParametersForTokenRequest(resource), new HttpHeaders());
}
我们可以通过为客户端凭据提供新的自定义访问令牌提供程序并修改方法来设置http标头,如下所示:
public OAuth2AccessToken obtainAccessToken(OAuth2ProtectedResourceDetails details, AccessTokenRequest request)
throws UserRedirectRequiredException, AccessDeniedException, OAuth2AccessDeniedException {
ClientCredentialsResourceDetails resource = (ClientCredentialsResourceDetails) details;
HttpHeaders headers1 = new HttpHeaders();
headers1.add("Content-Type", "application/x-www-form-urlencoded");
return retrieveToken(request, resource, getParametersForTokenRequest(resource), headers1);
}
您可以使类与ClientCredentialsAccessTokenProvider保持一致,并仅添加标题行。
最后一步是将此新类设置为Oauth2RestTemplate配置中的访问令牌。
oauth2RestTemplate.setAccessTokenProvider(new ClientCredentialsCustomAccessTokenProvider());
这对我有用!
这是答案的另一个变体,只是为了使用Lambda表达式覆盖默认的Accept Header拦截器:
@Bean
protected RestTemplate restTemplate() {
return new RestTemplate() {
@Override
public <T> RequestCallback acceptHeaderRequestCallback(Class<T> responseType) {
return request -> {
request.getHeaders().setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
};
}
};
}
如果您使用Spring启动提及身份验证方案,它将解决问题。
security:
oauth2:
client:
clientAuthenticationScheme: form