OAuth 2.0 访问令牌和刷新令牌 [英] OAuth 2.0 Access Tokens and Refresh Tokens

查看:59
本文介绍了OAuth 2.0 访问令牌和刷新令牌的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我很难理解刷新和访问令牌的正确用法.我知道刷新令牌与授权有关,访问令牌与身份验证有关.我想更好地解释我的用例,以便有人可以帮助我.我在 Google Merchant Center 中有一个多帐户中心.我想在我的代码中集成最新的 OAuth 2.0 身份验证机制.我做到了并且可以成功验证.我使用 Google Credential 机制来构建凭证对象,并在 httprequest 到 google 期间使用 httprequestinitializer 机制注入.当创建 google 凭据对象时,我看到在执行 googleCredential.getAccessToken() 时没有访问令牌,但是当我执行 googleCredential.refreshToken() 和 googleCredential.getAccessToken() 时,我得到一个 accessToken.但是,我正在测试令牌是如何创建的,并且我没有在请求中明确地将这些令牌传递给 google.我传递的只是带有客户端机密和其他私钥的 googleCredential 对象.我正在做的任务只是通过 cron 脚本将子帐户产品提要上传到谷歌.

我的问题是,

  1. 在此处传递 googleCredential 对象时,我是否必须处理此处的刷新令牌?(假设脚本运行超过一天)
  2. 什么时候应该使用刷新令牌和访问令牌,在上述用例中对我来说什么是正确的选择?(尽管目前我没有明确传递 googleCredential 对象以外的任何内容)
  3. 访问令牌和刷新令牌的有效期是多少(与上述用例无关,只是想知道,有人说刷新令牌为 14 天,有人说无限期直到用户撤销访问权限等)

如果有人澄清我并把我拉出来,我会很饱的.我知道这个平台主要是为了澄清代码问题,但我谷歌论坛也没有帮助.所以在这里发帖.

抱歉我太啰嗦了.

提前致谢.

解决方案

所谓的 OfflineCredentials 需要 刷新令牌.这些凭据可供未在浏览器中运行的应用程序使用(例如桌面应用程序或某些没有 UI 的批处理),因此无法执行 OAuth2 流程.

请查看使用 OAuth 2.0 访问 Google API

<块引用>

  1. 如有必要,刷新访问令牌.

访问令牌的生命周期有限.如果您的应用程序需要在单个访问令牌的生命周期之外访问 Google API,它可以获得刷新令牌.刷新令牌允许您的应用程序获取新的访问令牌.

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

有关离线访问的更多信息!

在 Java 中,它看起来像这样:

import com.google.api.ads.common.lib.auth.OfflineCredentials;导入 com.google.api.ads.common.lib.auth.OfflineCredentials.Api;导入 com.google.api.ads.common.lib.auth.OfflineCredentials.ForApiBuilder;导入 com.google.api.ads.common.lib.exception.OAuthException;导入 com.google.api.ads.common.lib.exception.ValidationException;导入 com.google.api.client.auth.oauth2.Credential;//...//生成离线凭证//使用先前创建的 OAuth2 刷新令牌(参见 API 示例)ForApiBuilder forApiBuilder = new OfflineCredentials.Builder().forApi(Api.ADWORDS);forApiBuilder.withClientSecrets(clientId, clientSecret);forApiBuilder.withRefreshToken(refreshToken);凭证凭证=空;尝试 {credential = forApiBuilder.build().generateCredential();} catch (OAuthException e) {throw new Exception("无法刷新给定的凭据:" + e.getMessage());} catch (ValidationException e) {throw new Exception("客户端 ID、客户端密码或刷新令牌无效:" + e.getMessage());}//构建会话//...

除了客户端 ID 和客户端密钥之外,还需要将刷新令牌传递给凭证生成器.使用有效的 OfflineCredentials,您现在可以为特定的 Google API 构建新会话.

关于您的第三个问题:请参阅以下问题的公认答案

此处是源代码,它展示了如何通过命令行获取一次 Google AdWords(参见范围)的刷新令牌.客户端 ID 和客户端密码必须作为命令行参数传递.

import java.io.BufferedReader;导入 java.io.InputStreamReader;导入 org.apache.commons.configuration.Configuration;导入 org.apache.commons.configuration.PropertiesConfiguration;导入 com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder;导入 com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.Api;导入 com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.GoogleClientSecretsForApiBuilder;导入 com.google.api.ads.common.lib.exception.ValidationException;导入 com.google.api.client.auth.oauth2.Credential;导入 com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;导入 com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;导入 com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;导入 com.google.api.client.googleapis.auth.oauth2.GoogleCredential;导入 com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;导入 com.google.api.client.http.javanet.NetHttpTransport;导入 com.google.api.client.json.jackson2.JacksonFactory;导入 com.google.common.collect.Lists;//...私有静态最终字符串范围=https://adwords.google.com/api/adwords";//此回调 URL 将允许您从成功屏幕复制令牌private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";public static void main(String[] args) 抛出异常 {如果(参数.长度!= 2){System.err.println(请提供客户端 ID 和密码作为命令行参数!");System.err.println("如果您没有客户端 ID 或密钥,请在 API 控制台中创建一个:https://code.google.com/apis/console#access");System.exit(1);}GoogleClientSecrets clientSecrets = null;尝试 {配置配置 = new PropertiesConfiguration();configuration.setProperty(api.adwords.clientId", args[0]);configuration.setProperty(api.adwords.clientSecret", args[1]);GoogleClientSecretsForApiBuilder googleClientSecretsForApiBuilder = new GoogleClientSecretsBuilder().forApi(Api.ADWORDS);googleClientSecretsForApiBuilder.from(配置);clientSecrets = googleClientSecretsForApiBuilder.build();} catch (ValidationException e) {System.err.println("无效的客户端ID或密码!");System.exit(1);}//获取 OAuth2 凭证凭证凭证 = getOAuth2Credential(clientSecrets);System.out.printf("你的刷新令牌是:%s
", credential.getRefreshToken());}}私有静态凭据 getOAuth2Credential(GoogleClientSecrets clientSecrets) 抛出异常 {/** 将访问类型设置为离线,以便可以刷新令牌.经过* 默认情况下,库会在可以时自动刷新令牌,但是* 这可以通过设置 api.adwords.refreshOAuth2Token=false 关闭*/GoogleAuthorizationCodeFlow authorizationFlow = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(), clientSecrets, Lists.newArrayList(SCOPE)).setAccessType("offline").build();String authorizeUrl = authorizationFlow.newAuthorizationUrl().setRedirectUri(CALLBACK_URL).build();System.out.println("将此网址粘贴到浏览器中:
" + authorizeUrl + '
');//等待授权码System.out.println("在此处输入您收到的代码:");String authorizationCode = new BufferedReader(new InputStreamReader(System.in)).readLine();//授权 OAuth2 令牌GoogleAuthorizationCodeTokenRequest tokenRequest = authorizationFlow.newTokenRequest(authorizationCode);tokenRequest.setRedirectUri(CALLBACK_URL);GoogleTokenResponse tokenResponse = tokenRequest.execute();//创建 OAuth2 凭证GoogleCredential 凭证 = new GoogleCredential.Builder().setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory()).setClientSecrets(clientSecrets).build();//设置授权凭证credential.setFromTokenResponse(tokenResponse);返回凭证;}

代码最初来自 Google AdWords API 示例.我的版本不是从配置文件中读取的,因为我不想将客户端 ID 和机密存储在某个资源文件中(我后来忘记删除了).这就是这些值作为参数传递给程序的原因.

I have difficult in understanding the proper usage of refresh and access tokens. I know that refresh tokens are related to authorization and access tokens are related to authentication.I would like to explain my use case better so that someone could help me out here. I have a Multi Account Center in Google Merchant Center. I would like to integrate the latest OAuth 2.0 authentication mechanism in my code. I did and could authenticate successfully. I use Google Credential mechanism of building a credential object and inject in using the httprequestinitializer mechanism during httprequest to google. When the google credential object is created , I see that there is no access tokens when I do a googleCredential.getAccessToken(), but then when I do a googleCredential.refreshToken() and then a googleCredential.getAccessToken() , I get an accessToken. However, I was testing how the tokens are created and I am not explicitly passing these tokens in the request to google. All I pass is just the googleCredential object with client secrets and other private keys. The task I am doing is just uploading the sub account product feeds to google via cron script.

My questions are,

  1. Do I have to take care of the refreshing tokens here while passing the googleCredential object here ? (Assume script runs for a more than a day)
  2. When should one use refresh tokens and access tokens, what would a proper choice for me in above use case? (Though for now I am not passing anything explicitly other than googleCredential Object)
  3. What is the validity time for a access token and refresh token(not related to above use case, just to know, some say 14 days for refresh tokens, some say indefinite till user revokes access , etc)

I would be great full if someone clarifies me and pulls me out. I know this platform is to clarify issues majorly on code but I google forum isn't helping either. So posting here.

Sorry for being very verbose.

Thanks in advance.

解决方案

A refresh token is required for so called OfflineCredentials. These are credentials, that can be used by applications, which are not running in a browser (e.g. desktop applications or some batch processing without UI) and therefore cannot perform an OAuth2 flow.

Please have a look at Using OAuth 2.0 to Access Google APIs

  1. Refresh the access token, if necessary.

Access tokens have limited lifetimes. If your application needs access to a Google API beyond the lifetime of a single access token, it can obtain a refresh token. A refresh token allows your application to obtain new access tokens.

Note: 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.

Some more information to Offline Access!

In Java, it will look like this:

import com.google.api.ads.common.lib.auth.OfflineCredentials;
import com.google.api.ads.common.lib.auth.OfflineCredentials.Api;
import com.google.api.ads.common.lib.auth.OfflineCredentials.ForApiBuilder;
import com.google.api.ads.common.lib.exception.OAuthException;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;

// ...

// Generate offline credentials
// With a previously created OAuth2 refresh token (see API examples)
ForApiBuilder forApiBuilder = new OfflineCredentials.Builder().forApi(Api.ADWORDS);
forApiBuilder.withClientSecrets(clientId, clientSecret);
forApiBuilder.withRefreshToken(refreshToken);

Credential credential = null;
try {
  credential = forApiBuilder.build().generateCredential();
} catch (OAuthException e) {
  throw new Exception("The given credential could not be refreshed: " + e.getMessage());
} catch (ValidationException e) {
  throw new Exception("Client ID, client secret or refresh token are not valid: " + e.getMessage());
}

// Build session
// ...

The refresh token need to be passed to the credential builder in addition to the client ID and the client secret. With the valid OfflineCredentials you are now able to build a new session for a specific Google API.

Regarding your third question: See the accepted answer of following question

Here the source code, which shows how to obtain a refresh token for Google AdWords (see scope) once via commandline. The client ID and the client secret must be passed as commandline arguments.

import java.io.BufferedReader;
import java.io.InputStreamReader;

import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.PropertiesConfiguration;

import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.Api;
import com.google.api.ads.common.lib.auth.GoogleClientSecretsBuilder.GoogleClientSecretsForApiBuilder;
import com.google.api.ads.common.lib.exception.ValidationException;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeTokenRequest;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.common.collect.Lists;

// ...

  private static final String SCOPE = "https://adwords.google.com/api/adwords";

  // This callback URL will allow you to copy the token from the success screen
  private static final String CALLBACK_URL = "urn:ietf:wg:oauth:2.0:oob";

  public static void main(String[] args) throws Exception {
    if (args.length != 2) {
      System.err.println("Please provide client ID and secret as commandline arguments!");
      System.err.println("If you do not have a client ID or secret, please create one in the API console: https://code.google.com/apis/console#access");
      System.exit(1);
    }

    GoogleClientSecrets clientSecrets = null;
    try {
      Configuration configuration = new PropertiesConfiguration();
      configuration.setProperty("api.adwords.clientId", args[0]);
      configuration.setProperty("api.adwords.clientSecret", args[1]);

      GoogleClientSecretsForApiBuilder googleClientSecretsForApiBuilder = new GoogleClientSecretsBuilder().forApi(Api.ADWORDS);
      googleClientSecretsForApiBuilder.from(configuration);

      clientSecrets = googleClientSecretsForApiBuilder.build();
    } catch (ValidationException e) {
      System.err.println("Invalid client ID or secret!");
      System.exit(1);
    }

    // Get the OAuth2 credential
    Credential credential = getOAuth2Credential(clientSecrets);

    System.out.printf("Your refresh token is: %s
", credential.getRefreshToken());
    }
  }

  private static Credential getOAuth2Credential(GoogleClientSecrets clientSecrets) throws Exception {
    /*
     * Set the access type to offline so that the token can be refreshed. By
     * default, the library will automatically refresh tokens when it can, but
     * this can be turned off by setting api.adwords.refreshOAuth2Token=false
     */
    GoogleAuthorizationCodeFlow authorizationFlow = new GoogleAuthorizationCodeFlow.Builder(new NetHttpTransport(), new JacksonFactory(), clientSecrets, Lists.newArrayList(SCOPE)).setAccessType("offline").build();

    String authorizeUrl = authorizationFlow.newAuthorizationUrl().setRedirectUri(CALLBACK_URL).build();
    System.out.println("Paste this url in your browser: 
" + authorizeUrl + '
');

    // Wait for the authorization code
    System.out.println("Type the code you received here: ");
    String authorizationCode = new BufferedReader(new InputStreamReader(System.in)).readLine();

    // Authorize the OAuth2 token
    GoogleAuthorizationCodeTokenRequest tokenRequest = authorizationFlow.newTokenRequest(authorizationCode);
    tokenRequest.setRedirectUri(CALLBACK_URL);
    GoogleTokenResponse tokenResponse = tokenRequest.execute();

    // Create the OAuth2 credential
    GoogleCredential credential = new GoogleCredential.Builder().setTransport(new NetHttpTransport()).setJsonFactory(new JacksonFactory()).setClientSecrets(clientSecrets).build();

    // Set authorized credentials
    credential.setFromTokenResponse(tokenResponse);

    return credential;
  }

The code is originally from a Goolge AdWords API example. My version is not reading from a configuration file, because I didn't want to store the client ID and secret in some resource file (which I forgot to remove later on). That's why the values are passed as arguments to the program.

这篇关于OAuth 2.0 访问令牌和刷新令牌的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆