Spring社交Reddit扩展 - OAuth 2 Access_token检索。 401错误

时间:2014-10-16 12:46:35

标签: spring oauth-2.0 spring-social resttemplate reddit

我正在尝试为Reddit's Api创建扩展程序。 Reddit跟随OAuth 2获取access_token。我使用spring RestTemplate来向Reddit发出所有POST请求。我能够根据文档成功完成第一阶段。用户被重定向到Reddit,他/她允许我的应用程序,Reddit然后用代码将我重定向回我的应用程序。但是,第二阶段似乎不起作用。我必须使用该代码发出另一个帖子请求:

https://ssl.reddit.com/api/v1/access_token

这是我尝试获取AccessGrant(从Reddit发回的accessstoken的SpringSocial包装器)。 Spring Social要求您扩展OAuth2Template并从那里实现身份验证过程。在典型的spring应用程序中,控制器将使用帮助程序调用RedditOAuth2Template.exchangeForAccess并将返回的AccessGrant保存到数据库中。

根据Reddit API Documentaiton,由于缺少基本身份验证的客户端凭据,因此会发生401响应。但是,我在createHeaders(String username,String password)方法中执行此操作。

公共类RedditOAuth2Template扩展了OAuth2Template {

private static final Logger LOG = LogManager.getLogger(RedditOAuth2Template.class);

private String client_id;
private String client_secret;

public RedditOAuth2Template(String clientId, String clientSecret) {
    super(clientId, clientSecret, RedditPaths.OAUTH_AUTH_URL, RedditPaths.OAUTH_TOKEN_URL);
    this.client_id = clientId;
    this.client_secret = clientSecret;
    setUseParametersForClientAuthentication(true);
}


@Override
@SuppressWarnings({"unchecked", "rawtypes"})
protected AccessGrant postForAccessGrant(String accessTokenUrl, MultiValueMap<String, String> parameters) {
    HttpHeaders headers = createHeaders(client_id, client_secret);
    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
    headers.set(accessTokenUrl, accessTokenUrl);
    HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<MultiValueMap<String, String>>(parameters, headers);
    ResponseEntity<Map> responseEntity = getRestTemplate().exchange(accessTokenUrl, HttpMethod.POST, requestEntity, Map.class);
    Map<String, Object> responseMap = responseEntity.getBody();
    return extractAccessGrant(responseMap);
}

/*
 Reddit requires client_id and client_secret be 
 placed via HTTP basic Auth when retrieving the access_token
 */
private HttpHeaders createHeaders(String username, String password) {
    String auth = username + ":" + password;
    byte[] encodedAuth = Base64.getEncoder().encode(auth.getBytes(Charset.forName("US-ASCII")));
    HttpHeaders headers = new HttpHeaders();
    String authHeader = "Basic " + new String(encodedAuth);
    headers.set("Authorization", authHeader);
    return headers;
}

private AccessGrant extractAccessGrant(Map<String, Object> result) {
    String accessToken = (String) result.get("access_token");
    String scope = (String) result.get("scope");
    String refreshToken = (String) result.get("refresh_token");
    // result.get("expires_in") may be an Integer, so cast it to Number first.  
    Number expiresInNumber = (Number) result.get("expires_in");
    Long expiresIn = (expiresInNumber == null) ? null : expiresInNumber.longValue();

    return createAccessGrant(accessToken, scope, refreshToken, expiresIn, result);
}

}

1 个答案:

答案 0 :(得分:0)

如果您正在为该端点获得401响应,那么您将执行少量错误之一,这些都与发送客户端ID和作为HTTP基本授权的秘密:

  • 不包括格式正确的授权标头(即Authorization: basic <b64 encoded credentials>
  • 不正确编码您的凭据的基础64
  • 不包括有效OAuth2客户端的client_id
  • 不包括客户ID和秘密
  • 之间的分号
  • 不包括秘密,或包括错误的秘密

您应该检查Basic客户端身份验证的每个阶段,并在每个阶段记录您的输出(或使用调试器检查它),以确保您不会遗漏任何内容。您还应检查生成的实际HTTP请求,并验证是否正在发送标头(某些HTTP库喜欢使用标头自由)