无法使用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; 
} 
+1

使用AdSense时仍然会出现此“invalid_grant”异常。客户端ID有效,范围为AdSenseScopes.ADSENSE。 AdSense Management API已激活。不知道如何解决它 – user12384512

+0

即使我使用NodeJS包装器,对我也很有帮助。我的问题是我用我的帐户电子邮件而不是应用程序的电子邮件地址。谢谢! –

+0

真是一个出色的答案!我在使用Google Sheets Java API时收到了JWT错误。没有运气找到解决方案。几乎不可能的(除了这个线程)找到一个工作的Java代码示例,通过服务帐户获取凭据到谷歌API服务。当我交换我的凭据以反映你的答案时,我现在能够通过Google Sheets API成功向私人提出请求。 此外,在使用图纸时,请确保允许在您的服务帐户的电子邮件地址(在您下载的json密钥/身份文件中)的私人工作表中(通过Share按钮)获得许可 – ganta