从OAuth1 3L迁移到OAuth2:

时间:2014-03-19 04:49:40

标签: google-oauth google-oauth-java-client

我尝试将现有的OAuth1.0 3L令牌迁移到OAuth2.0以获取Web应用。 我按照https://developers.google.com/accounts/docs/OAuth_ref的说明操作 尽管我付出了最大努力,但我还是得到了这样的答复: "无效的授权标题。"

要创建授权标头,我使用谷歌的Java客户端库1.0,我在应用程序中使用与谷歌日历聊天相同。 我正在使用访问令牌进行测试。令牌密钥,消费者密钥和消费者密钥无问题(即我可以使用这些凭据拨打Google日历等)。

这是我使用的代码:

    OAuthParameters oauthParameters = new OAuthParameters();
    oauthParameters.setOAuthConsumerKey("www.mywebsite.com"); // this is the same consumer key used by my app normally, without problem. mywebsite is an example, the real name is different
    oauthParameters.setOAuthConsumerSecret("XXXXX");
    oauthParameters.setOAuthToken("YYYYY");
    oauthParameters.setOAuthTokenSecret("ZZZZZZ");

    OAuthHmacSha1Signer signer = new OAuthHmacSha1Signer();
    OAuthHelper oauthHelper = new GoogleOAuthHelper(signer);
    String requestUrl = "https://accounts.google.com/o/oauth2/token";
    String header = oauthHelper.getAuthorizationHeader(requestUrl, "POST", oauthParameters);
    String payload = "grant_type=urn%3Aietf%3Aparams%3Aoauth%3Agrant-type%3Amigration%3Aoauth1&client_id="+clientId+"&client_secret="+clientSecret;

    HttpClient httpClient = new DefaultHttpClient();

    HttpPost httpPost = new HttpPost(requestUrl);
    httpPost.addHeader("Authorization", header);
    httpPost.addHeader("Content-Type", "application/x-www-form-urlencoded");
    httpPost.setEntity(new ByteArrayEntity(payload.getBytes()));
    String response = httpClient.execute(httpPost, new BasicResponseHandler());

这是由HttpClient生成的线迹:

>> "POST /o/oauth2/token HTTP/1.1[\r][\n]"
>> "Authorization: OAuth realm="", oauth_signature="ixVbjINI6pgPU2RqXGiQRbPGY%3D", oauth_nonce="486642280771700", oauth_signature_method="HMAC-SHA1", oauth_consumer_key="www.mywebsite.com", oauth_token="YYYYY", oauth_timestamp="1395127834"[\r][\n]"
>> "Content-Type: application/x-www-form-urlencoded[\r][\n]"
>> "Content-Length: 193[\r][\n]"
>> "Host: accounts.google.com[\r][\n]"
>> "Connection: Keep-Alive[\r][\n]"
>> "User-Agent: Apache-HttpClient/4.3.2 (java 1.5)[\r][\n]"
>> "[\r][\n]"
>> "grant_type=urn%ietf%params%oauth%grant-type%migration%oauth1&client_id=12345&client_secret=ABCDE"
<< "HTTP/1.1 400 Bad Request[\r][\n]"
<< "Cache-Control: no-cache, no-store, max-age=0, must-revalidate[\r][\n]"
<< "Pragma: no-cache[\r][\n]"
<< "Expires: Fri, 01 Jan 1990 00:00:00 GMT[\r][\n]"
<< "Date: Tue, 18 Mar 2014 07:30:39 GMT[\r][\n]"
<< "Content-Type: application/json[\r][\n]"
<< "X-Content-Type-Options: nosniff[\r][\n]"
<< "X-Frame-Options: SAMEORIGIN[\r][\n]"
<< "X-XSS-Protection: 1; mode=block[\r][\n]"
<< "Server: GSE[\r][\n]"
<< "Alternate-Protocol: 443:quic[\r][\n]"
<< "Transfer-Encoding: chunked[\r][\n]"
<< "[\r][\n]"
<< "5a[\r][\n]"
<< "{[\n]"
<< "  "error" : "invalid_request",[\n]"
<< "  "error_description" : "Invalid authorization header."[\n]"
<< "}"
<< "[\r][\n]"
<< "0[\r][\n]"
<< "[\r][\n]"

其中12345和ABCDE显然是真实OAuth2应用凭证的占位符。

我进行了双重和三重检查,OAuthParameters中设置的所有参数与当前使用OAuth1的正常代码使用的相同(即使使用逐步调试器来验证签名时的值由OAuthHmacSha1Signer.getSignature())计算。

我查看了当前使用OAuth1的Google客户端API发送的HTTP请求中的授权标头(并且工作正常),除了签名,随机数和时间戳之外,它们看起来与此迁移调用发送的相同。

我甚至尝试了一个失败的测试迁移请求,然后使用调试器运行旧代码并注入迁移调用使用的方法,URL,nonce和timestamp,并且由旧代码计算的签名是相同的,给定相同的参数。

为什么授权标头仍然被报告为无效的任何线索?

3 个答案:

答案 0 :(得分:1)

在跟进SimonM之后,事实证明该问题与用于签署迁移请求的基本字符串有关。

构建基本字符串以对迁移请求进行签名时,请确保该字符串使用 POST 方法(而非GET,就像访问许多Google API时的情况一样)并且根据migration documentation包含所有相关的迁移参数

根据OAuth1 spec,迁移请求的有效基本字符串应如下所示:

POST&安培; https://accounts.google.com/o/oauth2/token&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&grant_type=urn:ietf:params:oauth:grant-type:migration:oauth1&oauth_consumer_key=YOUR_CONSUMER_KEY&oauth_nonce=NONCE&oauth_signature_method=HMAC-SHA1&oauth_timestamp=1396414006&oauth_token=THE_TOKEN_TO_MIGRATE

请注意,出于可读性目的,以上是基本字符串的解码版本(有关更多示例,请查看OAuth1 spec)。

答案 1 :(得分:1)

生成基本字符串时,您需要确保在构造基本字符串之前对每个单独的参数进行URL编码。

根据sign OAuth 1.0 requests的oAuth文档,基本字符串由3个组件组成

  • HTTP请求方法
  • 请求发送到
  • 的基本网址
  • 请求中的参数的标准化字符串

构建基本字符串时,需要执行以下操作

  • 确保HTTP请求方法为POST
  • URL对基本网址进行编码
  • 确保三个POST正文参数[client_id,client_secret,grant_type]包含在规范化请求参数中
  • 确保每个参数都是单独的URL编码,然后对完整的规范化请求参数字符串进行URL编码。所以实际上,一些参数是双URL编码的。对于oauth_token
  • Using OAuth with the Google Data APIs#Signing Requests中提到了这种双重URL编码

只有在完成所有这些步骤后,才能使迁移请求生效,并且我收到了有效的refresh_token

以下是基本字符串示例

POST&https%3A%2F%2Faccounts.google.com%2Fo%2Foauth2%2Ftoken&client_id%3Dxxxxxxxxxx-xxxxxxxxxxxxxxxxxxxxxxxxxx.apps.googleusercontent.com%26client_secret%3Dxxxxxxxxxxxx%26grant_type%3Durn%253Aietf%253Aparams%253Aoauth%253Agrant-type%253Amigration%253Aoauth1%26oauth_consumer_key%3Dxxxxxxxxx%26oauth_nonce%3D4106001%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1400779530%26oauth_token%3D1%252FkklP1YPy_AULt7j_tttttt_tterwerkj_dfj45dflk

答案 2 :(得分:0)

OAuth2中的auth标头是一个承载令牌。它应该看起来像

Authorization: Bearer 0b79bab50daca910b000d4f1a2b675d604257e42
相关问题