无法使用Google API获取令牌[google-oauth-java-client-1.12.0-beta]服务帐户流
问题描述:
我正在使用Google API(版本为google-oauth-java-client-1.12.0-beta)获取OAuth2访问令牌但返回“invalid_grant”。 编号:https://developers.google.com/accounts/docs/OAuth2ServiceAccount无法使用Google API获取令牌[google-oauth-java-client-1.12.0-beta]服务帐户流
下面是代码:
import com.google.api.client.auth.jsontoken.JsonWebSignature;
import com.google.api.client.auth.jsontoken.JsonWebToken;
import com.google.api.client.auth.jsontoken.RsaSHA256Signer;
import com.google.api.client.auth.oauth2.TokenRequest;
import com.google.api.client.auth.oauth2.TokenResponse;
import com.google.api.client.http.GenericUrl;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.Clock;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
public class TestClient
{
private static PrivateKey getPrivateKey(String keyFile, String alias, String password)
throws KeyStoreException, IOException, NoSuchAlgorithmException, CertificateException, UnrecoverableKeyException
{
KeyStore keystore = KeyStore.getInstance("PKCS12");
keystore.load(new FileInputStream(keyFile), password.toCharArray());
PrivateKey privateKey = (PrivateKey) keystore.getKey(alias, password.toCharArray());
return privateKey;
}
public static void main(String[] args)
throws GeneralSecurityException, IOException
{
String password = "notasecret";
String alias = "privatekey";
String keyFile = "<private key file>.p12";
String serviceAccountScopes = "https://www.googleapis.com/auth/urlshortener";
String serviceAccountUser = "[email protected]mail.com";
String serviceAccountId = "<a/c id>.apps.googleusercontent.com";
JsonWebSignature.Header header = new JsonWebSignature.Header();
header.setAlgorithm("RS256");
header.setType("JWT");
JsonWebToken.Payload payload = new JsonWebToken.Payload(Clock.SYSTEM);
long currentTime = Clock.SYSTEM.currentTimeMillis();
payload.setIssuer(serviceAccountId)
.setAudience("https://accounts.google.com/o/oauth2/token")
.setIssuedAtTimeSeconds(currentTime/1000)
.setExpirationTimeSeconds(currentTime/1000 + 3600)
.setPrincipal(serviceAccountUser);
payload.put("scope", serviceAccountScopes);
System.out.println(payload.toPrettyString());
PrivateKey serviceAccountPrivateKey = getPrivateKey(keyFile, alias, password);
String assertion = RsaSHA256Signer.sign(serviceAccountPrivateKey, getJsonFactory(), header, payload);
TokenRequest request = new TokenRequest(getTransport(), getJsonFactory(), new GenericUrl(getTokenServerEncodedUrl()), "assertion");
request.put("grant_type", "urn:ietf:params:oauth:grant-type:jwt-bearer");
request.put("assertion", assertion);
TokenResponse resp = request.execute();
System.out.println("token : " + resp.getAccessToken());
}
private static String getTokenServerEncodedUrl()
{
return "https://accounts.google.com/o/oauth2/token";
}
private static JsonFactory getJsonFactory()
{
return new JacksonFactory();
}
private static HttpTransport getTransport()
{
return new NetHttpTransport();
}
}
结果:
Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
"error" : "invalid_grant"
}
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:103)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:303)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:323)
什么是这里的问题?任何暗示将不胜感激。
答
在Google服务和Google API客户端库上使用服务帐户时,您不必自己创建签名并构建智威汤逊代币,因为这里提供的只读实用程序类可简单地执行服务帐户授权OAuth 2.0。
但是,除了包含多种编程语言的详细说明和代码示例的Google云端硬盘文档外,此文档没有很好记录。你应该阅读: https://developers.google.com/drive/service-accounts#google_apis_console_project_service_accounts
一些问题,你的代码:
- 服务帐户的ID应该是形式:
<some-id>@developer.gserviceaccount.com
(是电子邮件,而不是客户端ID,我知道它的怪异) - 当您做Google Apps domain Wide delegation时,您只设置
principal
,但您当然不能在Gmail帐户上执行此操作,只能在管理员授权您访问其域的Google Apps帐户中进行操作:请勿设置它。
以下是OAuth 2.0 w/Service帐户在Java中的代码示例。
注意:您还需要下载the URL Shortener library。
/** Email of the Service Account */
private static final String SERVICE_ACCOUNT_EMAIL = "<some-id>@developer.gserviceaccount.com";
/** Path to the Service Account's Private Key file */
private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/<public_key_fingerprint>-privatekey.p12";
/**
* Build and returns a URL Shortner service object authorized with the service accounts.
*
* @return URL Shortner service object that is ready to make requests.
*/
public static Drive getDriveService() throws GeneralSecurityException, IOException, URISyntaxException {
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
GoogleCredential credential = new GoogleCredential.Builder()
.setTransport(httpTransport)
.setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
.setServiceAccountScopes(UrlshortenerScopes.URLSHORTENER)
.setServiceAccountPrivateKeyFromP12File(
new java.io.File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
.build();
Urlshortener service = new Urlshortener.Builder(httpTransport, jsonFactory, null)
.setHttpRequestInitializer(credential).build();
return service;
}
使用AdSense时仍然会出现此“invalid_grant”异常。客户端ID有效,范围为AdSenseScopes.ADSENSE。 AdSense Management API已激活。不知道如何解决它 – user12384512
即使我使用NodeJS包装器,对我也很有帮助。我的问题是我用我的帐户电子邮件而不是应用程序的电子邮件地址。谢谢! –
真是一个出色的答案!我在使用Google Sheets Java API时收到了JWT错误。没有运气找到解决方案。几乎不可能的(除了这个线程)找到一个工作的Java代码示例,通过服务帐户获取凭据到谷歌API服务。当我交换我的凭据以反映你的答案时,我现在能够通过Google Sheets API成功向私人提出请求。 此外,在使用图纸时,请确保允许在您的服务帐户的电子邮件地址(在您下载的json密钥/身份文件中)的私人工作表中(通过Share按钮)获得许可 – ganta