无法使用Google API 获取服务帐户流的令牌

我正在使用Google API(版本为google-oauth-java-client-1.12.0-beta)获取OAuth2访问令牌但返回“invalid_grant”。 参考: https : //developers.google.com/accounts/docs/OAuth2ServiceAccount

这是代码:

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 = ".p12"; String serviceAccountScopes = "https://www.googleapis.com/auth/urlshortener"; String serviceAccountUser = "user1@gmail.com"; String serviceAccountId = ".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客户端库上使用服务帐户时,您不必自己创建签名并构建JWT令牌,因为有读取使用的实用程序类只需通过OAuth 2.0执行服务帐户授权。

但是,除了Google Drive文档中包含多种编程语言的详细说明和代码示例之外,这一点并没有得到很好的记录。 您应该阅读: https : //developers.google.com/drive/service-accounts#google_apis_console_project_service_accounts

您的代码存在一些问题:

  • 服务帐户的ID应采用以下格式: @developer.gserviceaccount.com (是的是电子邮件而不是客户端ID,我知道这很奇怪)
  • 您只能在执行Google Apps域广泛授权时设置principal ,但当然,您无法在Gmail帐户上执行此操作,仅限于您已授予管理员访问权限的域的Google Apps帐户,因此在您的情况下:请勿设置它。

以下是使用Java的OAuth 2.0 w / Service帐户的代码示例。

注意:您还需要下载URL Shortener库 。

 /** Email of the Service Account */ private static final String SERVICE_ACCOUNT_EMAIL = "@developer.gserviceaccount.com"; /** Path to the Service Account's Private Key file */ private static final String SERVICE_ACCOUNT_PKCS12_FILE_PATH = "/path/to/-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; }