尝试使用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")
答案 0 :(得分:2)
在以下ClientCredentialsAccessTokenProvider方法中设置了用于访问Oauth2Restemplate中令牌的http标头(因为授予类型是客户端凭据)
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());
这对我有用!
答案 1 :(得分:1)
这是答案的另一个变体,只是使用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));
};
}
};
}
答案 2 :(得分:0)
如果您使用的是Spring Boot,请以表格形式提及身份验证方案,它将解决此问题。
security:
oauth2:
client:
clientAuthenticationScheme: form