【问题标题】:Spring Social Reddit Extension - OAuth 2 Access_token retrieval. 401 ErrorSpring Social Reddit 扩展 - OAuth 2 Access_token 检索。 401 错误
【发布时间】:2014-12-11 20:19:08
【问题描述】:

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

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

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

根据 Reddit API Documentaiton,由于缺少通过 HTTP 基本身份验证的客户端凭据,会发生 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);
}

}

【问题讨论】:

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


    【解决方案1】:

    如果您收到该端点的 401 响应,则说明您做错了少数事情之一,所有这些都与将客户端 ID 和密钥作为 HTTP 基本授权发送有关:

    • 不包括格式正确的授权标头(即Authorization: basic &lt;b64 encoded credentials&gt;
    • 未正确使用 base 64 对您的凭据进行编码
    • 不包括用于有效 OAuth2 客户端的 client_id
    • 客户端 ID 和密码之间不包括分号
    • 不包括秘密,或包括错误的秘密

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

    【讨论】:

      猜你喜欢
      • 2014-06-01
      • 2020-04-10
      • 1970-01-01
      • 2015-04-28
      • 1970-01-01
      • 1970-01-01
      • 2011-12-19
      • 2011-03-19
      • 2013-11-13
      相关资源
      最近更新 更多