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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/36214968/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 17:34:31  来源:igfitidea点击:

How to get access token using gmail api

javagoogle-apigmail-api

提问by tqjustc

I got the authorization code following this document. But when I tried to get access token, I always got errors. Can anyone help me ?

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

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 "";
}

when I ran this code, the output is: 400 Bad Request

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

回答by newhouse

You are not using the right endpoint. Try to change the authURLto https://www.googleapis.com/oauth2/v4/token

您没有使用正确的端点。尝试更改authURLhttps://www.googleapis.com/oauth2/v4/token

From the documentation:

从文档:

To make this token request, send an HTTP POST request to the /oauth2/v4/token endpoint

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

The actual request might look like the following:

实际请求可能如下所示:

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

Referencehttps://developers.google.com/identity/protocols/OAuth2InstalledApp#handlingtheresponse

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

回答by Benoit Vanalderweireldt

For me your request is fine, I tried it using Curl, I also get a 'HTTP/1.1 400 Bad Request' with the reason why it failed 'invalid_grant' :

对我来说,您的请求很好,我使用 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'

I receive (HTTP/1.1 400 Bad Request) :

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

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


Now using HttpClient from Apache :

现在使用 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()));

I see in my console :

我在控制台中看到:

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


Are you sure the code you are using is still valid ? Can you try with a new one ?

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

回答by SkyWalker

How to get access token using gmail api?

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

Ans:As per your following tutorial, you are using OAuth 2.0. So there is a basic pattern for accessing a Google API using OAuth 2.0. It follows 4 steps:

Ans:根据您的以下教程,您正在使用OAuth 2.0. 因此,有一个使用OAuth 2.0. 它遵循4个步骤:

  1. Obtain OAuth 2.0 credentials from the Google Developers Console.
  2. Obtain an access token from the Google Authorization Server.
  3. Send the access token to an API.
  4. Refresh the access token, if necessary.
  1. 从 Google Developers Console 获取 OAuth 2.0 凭据。
  2. 从 Google 授权服务器获取访问令牌。
  3. 将访问令牌发送到 API。
  4. 如有必要,刷新访问令牌。

For details, you can follow the tutorial - Using OAuth 2.0 to Access Google APIs

详情可以参考教程 - Using OAuth 2.0 to Access Google APIs

You have to visit the Google Developers Consoleto obtain OAuth 2.0 credentials such as a client IDand client secretthat are known to both Google and your application

您要访问的谷歌开发者控制台获取的OAuth 2.0凭证,如client IDclient secret已知到谷歌和你的应用程序



Root Cause Analysis:

根本原因分析:

Issue-1:

问题 1:

After studying your code, some lacking are found. If your code runs smoothly, then the code always give an empty string. Because your AccessToken()method always return return "";

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

Issue-2:

问题 2:

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

Your try catch block is going exception block. Because, it seems that you have not completed your code properly. You have missed encodingas well as using JSONObjectwhich prepares the access token. So it is giving output as

您的 try catch 块将变为异常块。因为,您似乎没有正确完成代码。您已经错过encoding以及使用JSONObjectwhich 准备访问令牌。所以它给出的输出为

Error.

错误。

Solution:

解决方案:

I got that your code is similar with this tutorial

我知道您的代码与本教程类似

As your code needs more changes to solve your issue. So I offer you to use LinkedHashMapor ArrayList. Those will provide easier way to make solution. So I give you 2 sample code to make your life easier. You can choose any of them. You need to change refresh_token, client id, client secret and grant typeas yours.

由于您的代码需要更多更改来解决您的问题。所以我建议你使用LinkedHashMapArrayList。这些将提供更简单的方法来解决。所以我给你 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;
}

For accessing google play android developer api, you need to pass the previous refresh token to get access token

访问google play android developer 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;
}

Resource Link:

资源链接:

Hope that, this samplesand resource linkwill help you to solve your issue and get access of access token.

希望,这samplesresource link将帮助你解决你的问题,得到的访问access token



What is 400 bad request?

什么是 400 错误请求?

Ans:It indicates that the query was invalid. Parent ID was missing or the combination of dimensions or metrics requested was not valid.

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

Recommended Action:You need to make changes to the API query in order for it to work.

推荐的操作:您需要对 API 查询进行更改才能使其正常工作。

For HTTP/1.1 400 Bad Request error, you can go through my another answer. It will help you to make sense about which host you need to useand which conditions you need to apply.

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

Why token expires? What is the limit of token?

为什么令牌会过期?代币上限是多少?

A token might stop working for one of these reasons:

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

  1. The user has revokedaccess.
  2. The token has not been used for six months.
  3. The user changed passwordsand the token contains Gmail, Calendar, Contacts, or Hangouts scopes.
  4. The user account has exceeded a certain number of token requests.
  1. 用户具有revoked访问权限。
  2. 令牌尚未用于six months
  3. user changed passwords该标记包含Gmail,日历,联系人,或Hangouts范围。
  4. 用户帐户具有exceeded a certain number of token requests.

There is currently a limit of 25 refresh tokens per user account per client. If the limit is reached, creating a new token automatically invalidates the oldest token without warning. This limit does not apply to service accounts.

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

Which precautions should be followed?

应遵循哪些预防措施?

Precautions - 1:

注意事项 - 1:

Some requests require an authentication step where the user logs in with their Google account. After logging in, the user is asked whether they are willing to grant the permissions that your application is requesting. This process is called user consent.

If the user grants the permission, the Google Authorization Server sends your application an access token (or an authorization code that your application can use to obtain an access token). If the user does not grant the permission, the server returns an error.

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

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

Precautions - 2:

注意事项 - 2:

If an access token is issued for the Google+ API, it does not grant access to the Google Contacts API. You can, however, send that access token to the Google+ API multiple times for similar operations.

如果为 Google+ API 颁发了访问令牌,则不会授予对 Google Contacts API 的访问权限。但是,您可以多次将该访问令牌发送到 Google+ API 以进行类似操作。

Precautions - 3:

注意事项 - 3:

An access token typically has an expiration date of 1 hour, after which you will get an error if you try to use it. Google Credentialtakes care of automatically "refreshing" the token, which simply means getting a new access token.

Save refresh tokens in secure long-term storage and continue to use them as long as they remain valid. Limits apply to the number of refresh tokens that are issued per client-user combination, and per user across all clients, and these limits are different. If your application requests enough refresh tokens to go over one of the limits, older refresh tokens stop working.

访问令牌通常具有 1 小时的到期日期,如果您尝试使用它,您将在此后收到错误消息。Google Credential负责自动“刷新”令牌,这意味着获取新的访问令牌。

将刷新令牌保存在安全的长期存储中,只要它们仍然有效,就可以继续使用它们。限制适用于每个客户端-用户组合以及跨所有客户端的每个用户发出的刷新令牌数,这些限制是不同的。如果您的应用程序请求足够的刷新令牌以超过其中一个限制,则较旧的刷新令牌将停止工作。

回答by F?rat Kocabay

Firstly, you must look this page :

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

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

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

The value you see in the query parameter code is a string you have to post to google in order to get the access token.

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

After the web server receives the authorization code, it may exchange the authorization code for an access token and a refresh token. This request is an HTTPS POST to the URL https://www.googleapis.com/oauth2/v3/tokenPOST /oauth2/v3/token HTTP/1.1 content-type: application/x-www-form-urlencoded

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

code=4/v4-CqVXkhiTkn9uapv6V0iqUmelHNnbLRr1EbErzkQw#&redirect_uri=&client_id=&scope=&client_secret=************&grant_type=authorization_code https://developers.google.com/identity/protocols/OAuth2WebServer

代码=4/v4-CqVXkhiTkn9uapv6V0iqUmelHNnbLRr1EbErzkQw#&redirect_uri=&client_id=&scope=&client_secret=************&grant_type=authorization_code https://developers.google.com/identity/protocols/OAuth2WebServer

回答by Yoav Aharoni

I think I understand what's wrong:

我想我明白出了什么问题:

  1. as @newhouse said, you should POST to https://www.googleapis.com/oauth2/v4/tokenand not https://accounts.google.com/o/oauth2/token(@newhouse I gave you a +1 :) )

    (https://www.googleapis.com/oauth2/v4/tokenis for getting the authorization_codeand https://accounts.google.com/o/oauth2/tokenis for getting the code).

  2. You can't use the same codemore than once.

    Everything else seems in order so, if you keep getting 400, you are probably trying to use the codeyou got more than one time (then you'll get 400 every time, again and again).

  1. 正如@newhouse 所说,你应该发帖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,一次又一次)。

* You should also lose the con.setRequestProperty("Host", "www.googleapis.com");

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

回答by Umang Joshi

Refer : https://developers.google.com/android-publisher/authorization

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

You already have authorization code that is called "refresh token". Please keep it in safe place. You can use "refresh token" to generate "access token".

您已经拥有名为“刷新令牌”的授权代码。请妥善保管。您可以使用“刷新令牌”来生成“访问令牌”。

To get "access token", please make a post request to following URL

要获取“访问令牌”,请向以下 URL 发出发布请求

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

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

Parameters:

参数:

  • grant_type
  • client_id
  • client_secret
  • refresh_token
  • 授权类型
  • 客户编号
  • 客户秘密
  • 刷新令牌

where "grant_type" should be "refresh_token"

其中“grant_type”应该是“refresh_token”

We are using PHP to do same, here is PHP's code for your reference

我们正在使用 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);

Hope it will help you.

希望它会帮助你。