问题 如何使用gmail api获取访问令牌


我收到了授权码 这个文件。但是当我试图获得访问令牌时,我总是遇到错误。谁能帮我 ?

public String AccessToken()
{
    String accessToken = "";
    StringBuilder strBuild = new StringBuilder();

    String authURL = "https://accounts.google.com/o/oauth2/token?";
    String code = "4/SVisuz_x*********************";
    String client_id = "******************e.apps.googleusercontent.com";
    String client_secret = "*******************";
    String redirect_uri = "urn:ietf:wg:oauth:2.0:oob";
    String grant_type="authorization_code";
    strBuild.append("code=").append(code)
            .append("&client_id=").append(client_id)
            .append("&client_secret=").append(client_secret)
            .append("&redirect_uri=").append(redirect_uri)
            .append("&grant_type=").append(grant_type);
    System.out.println(strBuild.toString());
    try{
        URL obj = new URL(authURL);
        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
        con.setDoOutput(true);
        con.setRequestMethod("POST");

        con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");
        con.setRequestProperty("Host", "www.googleapis.com");

        //BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(con.getOutputStream()));
        //bw.write(strBuild.toString());
        //bw.close();

        DataOutputStream wr = new DataOutputStream(con.getOutputStream());
        wr.writeBytes(strBuild.toString());
        wr.flush();
        wr.close();

        //OutputStreamWriter out = new OutputStreamWriter(con.getOutputStream());
        System.out.println(con.getResponseCode());
        System.out.println(con.getResponseMessage());             

    } catch (Exception e)
    {
        System.out.println("Error.");
    }
    return "";
}

当我运行此代码时,输​​出是: 400 Bad Request


3292
2018-03-25 06:12


起源

你得到了什么错误? - Jay Lee
@JayLee输出是一个字: Error - tqjustc
你在输出中看到msg“无效的字符串值”吗? - Bhunnu Baba
@tqjustc你能提供吗? e.printStackTrace(); 从你的拦截块?这将有助于为您提供适当的解决方案。 - SkyWalker
@SkyWalker它仍然打印:400,错误请求 - tqjustc


答案:


如何使用gmail api获取访问令牌?

答: 按照 你的以下教程, 您正在使用 OAuth 2.0。因此,有一种使用Google API访问的基本模式 OAuth 2.0。它遵循4个步骤:

  1. 从Google Developers Console获取OAuth 2.0凭据。
  2. 从Google Authorization Server获取访问令牌。
  3. 将访问令牌发送到API。
  4. 如有必要,刷新访问令牌。

有关详细信息,您可以按照教程 - 使用OAuth 2.0访问Google API

你必须访问 Google Developers Console 获取OAuth 2.0凭据,例如 client ID 和 client secret 谷歌和您的应用程序都知道


根本原因分析:

问题1:

在研究了你的代码后,发现了一些缺乏的代码。如果代码运行顺畅,那么代码总是给出一个空字符串。因为你的 AccessToken() 方法总是返回 return "";

问题2:

 catch (Exception e)
    {
        System.out.println("Error.");
    }

你的try catch块正在异常阻止。因为,您似乎还没有正确完成代码。你错过了 encoding 以及使用 JSONObject 准备访问令牌。所以它输出为

错误。

解:

我知道你的代码与此类似 教程

因为您的代码需要更多更改来解决您的问题。所以我提供你使用 LinkedHashMap的 要么 数组列表。这些将提供更简单的解决方案。所以我给你2个示例代码,让你的生活更轻松。你可以选择其中任何一个。你需要改变 refresh_token, client id, client secret and grant type 就像你的。

private String getAccessToken()
{
    try
    {
        Map<String,Object> params = new LinkedHashMap<>();
        params.put("grant_type","refresh_token");
        params.put("client_id",[YOUR CLIENT ID]);
        params.put("client_secret",[YOUR CLIENT SECRET]);
        params.put("refresh_token",[YOUR REFRESH TOKEN]);

        StringBuilder postData = new StringBuilder();
        for(Map.Entry<String,Object> param : params.entrySet())
        {
            if(postData.length() != 0)
            {
                postData.append('&');
            }
            postData.append(URLEncoder.encode(param.getKey(),"UTF-8"));
            postData.append('=');
            postData.append(URLEncoder.encode(String.valueOf(param.getValue()),"UTF-8"));
        }
        byte[] postDataBytes = postData.toString().getBytes("UTF-8");

        URL url = new URL("https://accounts.google.com/o/oauth2/token");
        HttpURLConnection con = (HttpURLConnection)url.openConnection();
        con.setDoOutput(true);
        con.setUseCaches(false);
        con.setRequestMethod("POST");
        con.getOutputStream().write(postDataBytes);

        BufferedReader  reader = new BufferedReader(new InputStreamReader(con.getInputStream()));
        StringBuffer buffer = new StringBuffer();
        for (String line = reader.readLine(); line != null; line = reader.readLine())
        {
            buffer.append(line);
        }

        JSONObject json = new JSONObject(buffer.toString());
        String accessToken = json.getString("access_token");
        return accessToken;
    }
    catch (Exception ex)
    {
        ex.printStackTrace(); 
    }
    return null;
}

对于 访问谷歌播放Android开发人员API,你需要通过   先前的刷新令牌以获取访问令牌

private String getAccessToken(String refreshToken){

HttpClient client = new DefaultHttpClient();
HttpPost post = new HttpPost("https://accounts.google.com/o/oauth2/token");
try 
{
    List<NameValuePair> nameValuePairs = new ArrayList<NameValuePair>(4);
    nameValuePairs.add(new BasicNameValuePair("grant_type",    "refresh_token"));
    nameValuePairs.add(new BasicNameValuePair("client_id",     GOOGLE_CLIENT_ID));
    nameValuePairs.add(new BasicNameValuePair("client_secret", GOOGLE_CLIENT_SECRET));
    nameValuePairs.add(new BasicNameValuePair("refresh_token", refreshToken));
    post.setEntity(new UrlEncodedFormEntity(nameValuePairs));

    org.apache.http.HttpResponse response = client.execute(post);
    BufferedReader reader = new BufferedReader(new InputStreamReader(response.getEntity().getContent()));
    StringBuffer buffer = new StringBuffer();
    for (String line = reader.readLine(); line != null; line = reader.readLine())
    {
        buffer.append(line);
    }

    JSONObject json = new JSONObject(buffer.toString());
    String accessToken = json.getString("access_token");

    return accessToken;

}
catch (IOException e) { e.printStackTrace(); }

return null;
}

资源链接:

希望,这个 samples 和 resource link 将帮助您解决您的问题并获得访问权限 access token


什么是400坏请求?

答: 它表示查询无效。缺少父ID或请求的维度或指标组合无效。

建议操作: 您需要更改API查询才能使其生效。

对于 HTTP/1.1 400 Bad Request error,你可以通过 我的另一个   回答它会帮助你理解 which host you need to use 以及您需要申请的条件

为什么令牌到期?令牌的限制是什么?

由于以下原因之一,令牌可能会停止工作:

  1. 用户有 revoked 访问。
  2. 令牌尚未用于 six months
  3. user changed passwords 并且令牌包含Gmail,日历, 联系人或环聊范围。
  4. 用户帐户有 exceeded a certain number of token requests

currently a limit of 25 refresh tokens per user account per client。如果达到限制,则创建新令牌会自动使最旧的令牌无效而不会发出警告。此限制不适用于服务帐户。

应遵循哪些预防措施?

注意事项 - 1:

某些请求需要用户登录的身份验证步骤   使用他们的Google帐户。登录后,将询问用户是否   他们愿意授予您的应用程序所具有的权限   请求。此过程称为用户同意。

如果用户授予权限,则为Google授权服务器   向您的应用程序发送访问令牌(或授权代码)   您的应用程序可用于获取访问令牌)。如果用户这样做   如果不授予权限,服务器将返回错误。

注意事项 - 2:

如果为Google+ API发放了访问令牌,则不会授予   访问Google通讯录API。但是,您可以发送该访问权限   对于类似的操作,多次将Google+标记到Google+ API。

注意事项 - 3:

访问令牌通常具有1小时的到期日期   如果您尝试使用它,您将收到错误。 Google凭据   自动“刷新”令牌,这只是意味着   获取新的访问令牌。

在安全的长期存储中保存刷新令牌并继续使用   只要他们仍然有效,他们。限制适用于数量   刷新每个客户端 - 用户组合和每个发布的令牌   所有客户的用户,这些限制是不同的。如果你的   应用程序请求足够的刷新令牌来覆盖其中一个   限制,旧的刷新令牌停止工作。


7
2018-03-28 16:41



现在的问题是我甚至无法打印出http消息。它总是会出错。我检查了你的另一个答案。但我仍然无法得到正确的答案 - tqjustc
@tqjustc我用一些示例和资源链接更新了我的答案。请检查并提供给我更新,以便我可以给你更好的反馈。 - SkyWalker


您没有使用正确的端点。试着改变 authURL 至 https://www.googleapis.com/oauth2/v4/token

从文档:

要发出此令牌请求,请向/ oauth2 / v4 / token端点发送HTTP POST请求

实际请求可能如下所示:

POST /oauth2/v4/token HTTP/1.1
Host: www.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/v6xr77ewYqhvHSyW6UJ1w7jKwAzu&
client_id=8819981768.apps.googleusercontent.com&
client_secret=your_client_secret&
redirect_uri=https://oauth2-login-demo.appspot.com/code&
grant_type=authorization_code

参考  https://developers.google.com/identity/protocols/OAuth2InstalledApp#handlingtheresponse


3
2018-03-27 18:55



@newhourse我仍然得到相同的错误输出: 400 Bad Request。 - tqjustc
尝试使用编码你的参数 URLEncoder.encode(param, "UTF-8"); - newhouse
不,它仍然无法正常工作 - tqjustc


对我来说你的要求很好,我尝试使用Curl,我也得到一个'HTTP / 1.1 400错误请求',因为它失败了'invalid_grant':

curl -X POST https://www.googleapis.com/oauth2/v4/token -d 'code=4/SVisuz_x*********************&client_id=*******************7vet.apps.googleusercontent.com&client_secret=***************&redirect_uri=https://oauth2-login-demo.appspot.com/code&grant_type=authorization_code'

我收到(HTTP / 1.1 400错误请求):

{
 "error": "invalid_grant",
 "error_description": "Code was already redeemed."
}

现在使用Apache的HttpClient:

URL obj = new URL(authURL);
HttpClient client = HttpClientBuilder.create().build();
HttpPost post = new HttpPost(authURL);
post.addHeader("Content-Type", "application/x-www-form-urlencoded");
post.addHeader("Host", "www.googleapis.com");
post.setEntity(new StringEntity(strBuild.toString()));

HttpResponse resp = client.execute(post);
System.out.println(resp.getStatusLine());
System.out.println(EntityUtils.toString(resp.getEntity()));

我在我的控制台中看到:

HTTP/1.1 400 Bad Request
{
 "error": "invalid_grant",
 "error_description": "Code was already redeemed."
}

您确定您使用的代码仍然有效吗?你可以尝试新的吗?


0
2018-03-28 04:01





首先,您必须查看此页面:

https://developers.google.com/gmail/api/auth/web-server#create_a_client_id_and_client_secret

您在查询参数代码中看到的值是您必须发布到Google才能获取访问令牌的字符串。

在Web服务器接收到授权代码之后,它可以交换访问令牌和刷新令牌的授权代码。此请求是URL的HTTPS POST https://www.googleapis.com/oauth2/v3/token POST / oauth2 / v3 / token HTTP / 1.1 content-type:application / x-www-form-urlencoded

代码= 4 / V4-CqVXkhiTkn9uapv6V0iqUmelHNnbLRr1EbErzkQw#&REDIRECT_URI =&CLIENT_ID =&范围=&client_secret = ************&grant_type = authorization_code https://developers.google.com/identity/protocols/OAuth2WebServer


0
2018-03-31 13:28





我想我明白了什么是错的:

  1. 正如@newhouse所说,你应该POST到 https://www.googleapis.com/oauth2/v4/token 并不是 https://accounts.google.com/o/oauth2/token (@newhouse我给你+1 :))

    https://www.googleapis.com/oauth2/v4/token 是为了获得 authorization_code 和 https://accounts.google.com/o/oauth2/token 是为了获得 code)。

  2. 你不能使用相同的 code 不止一次。

    其他一切看起来都是有序的,如果你继续得到400,你可能正在尝试使用 code 你有不止一次(那么你每次都会得到400次,一次又一次)。

*你也应该失去 con.setRequestProperty("Host", "www.googleapis.com"); 


0
2018-04-03 18:12





参考: https://developers.google.com/android-publisher/authorization

您已经拥有名为“刷新令牌”的授权码。请保管在安全的地方。您可以使用“刷新令牌”来生成“访问令牌”。

要获取“访问令牌”,请向以下网址发帖请求

https://accounts.google.com/o/oauth2/token

参数:

  • grant_type
  • CLIENT_ID
  • client_secret
  • refresh_token

其中“grant_type”应为“refresh_token”

我们使用PHP来做同样的事情,这里是PHP的代码供您参考

    $curl = curl_init();

    curl_setopt_array($curl, array(
    CURLOPT_RETURNTRANSFER => 1,
    CURLOPT_URL => 'https://accounts.google.com/o/oauth2/token',
    CURLOPT_USERAGENT => 'Pocket Experts Services',
    CURLOPT_POST => 1,
    CURLOPT_POSTFIELDS => array(
    "grant_type" => "refresh_token",
    "client_id" => $GOOGLE_CLIENT_ID,
    "client_secret" => $GOOGLE_CLIENT_SECRET,
    "refresh_token" => $GOOGLE_REFRESH_TOKEN,
    )));


    // Send the request & save response to $resp
    $resp = curl_exec($curl);

希望它会对你有所帮助。


0
2018-04-27 10:11