有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

无法为服务帐户流使用Google API[googleoauthjavaclient1.12.0beta]获取令牌

我正在使用Google API(版本Google-oauth-java-client-1.12.0-beta)获取OAuth2访问令牌,但返回“无效的授权”。 参考: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 = "<private key file>.p12";
    String serviceAccountScopes = "https://www.googleapis.com/auth/urlshortener";
    String serviceAccountUser = "user1@gmail.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)

这里有什么问题?任何暗示都将不胜感激


共 (1) 个答案

  1. # 1 楼答案

    当在Google Services和Google API客户端库上使用服务帐户时,您不必自己创建签名和构造JWT令牌,因为有read to use实用程序类可以通过OAuth 2.0简单地执行服务帐户授权

    然而,除了包含多种编程语言的详细解释和代码示例的Google Drive文档外,这并没有很好的文档记录。你应该读到: 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帐户上设置,当然,只能在管理员授予你访问权限的谷歌应用程序帐户上设置,所以在你的情况下:不要设置它

    下面是OAuth 2.0 w/Service accounts在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;
    }