A 刷新令牌需要所谓的离线凭证。这些是可由不在浏览器中运行的应用程序使用的凭据(例如桌面应用程序或一些没有 UI 的批处理),因此无法执行 OAuth2 流程。
请看一下使用 OAuth 2.0 访问 Google API https://developers.google.com/accounts/docs/OAuth2
- 如有必要,请刷新访问令牌。
访问令牌的生命周期有限。如果您的应用程序需要在单个访问令牌的生命周期之外访问 Google API,则它可以获得刷新令牌。刷新令牌允许您的应用程序获取新的访问令牌。
注意:将刷新令牌保存在安全的长期存储中,并在它们仍然有效时继续使用它们。限制适用于每个客户端-用户组合以及所有客户端上的每个用户颁发的刷新令牌的数量,并且这些限制是不同的。如果您的应用程序请求足够的刷新令牌来超过其中一项限制,则旧的刷新令牌将停止工作。
更多信息离线访问 https://developers.google.com/accounts/docs/OAuth2WebServer#offline!
在 Java 中,它看起来像这样:
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
// ...
除了客户端 ID 和客户端密钥之外,还需要将刷新令牌传递给凭据生成器。使用有效的 OfflineCredentials,您现在可以为特定的 Google API 构建新会话。
关于你的第三个问题:请参阅以下已接受的答案question https://stackoverflow.com/questions/8953983/do-google-refresh-token-expire
这里是源代码,展示了如何获取刷新令牌Google AdWords(参见范围)通过命令行一次。客户端 ID 和客户端密钥必须作为命令行参数传递。
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\n", 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: \n" + authorizeUrl + '\n');
// 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;
}
该代码最初来自Google AdWords API 示例 https://github.com/googleads/googleads-java-lib/blob/master/examples/adwords_axis/src/main/java/adwords/axis/auth/GetRefreshToken.java。我的版本不是从配置文件中读取,因为我不想将客户端 ID 和机密存储在某些资源文件中(我后来忘记删除它)。这就是为什么这些值作为参数传递给程序的原因。