2013-01-07 11 views
8

Tôi đang sử dụng API Google (phiên bản google-oauth-java-client-1.12.0-beta) để nhận mã thông báo truy cập OAuth2 nhưng đã quay lại "invalid_grant". Ref: https://developers.google.com/accounts/docs/OAuth2ServiceAccountKhông thể nhận mã thông báo bằng API Google [google-oauth-java-client-1.12.0-beta] cho luồng tài khoản dịch vụ

Đây là mã:

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]"; 
    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(); 
    } 
} 

Kết quả:

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) 

các vấn đề ở đây là gì? bất kỳ gợi ý nào sẽ được đánh giá cao.

Trả lời

7

Khi sử dụng Tài khoản dịch vụ trên Dịch vụ của Google và thư viện Ứng dụng API của Google, bạn không phải tạo chữ ký và tự xây dựng mã JWT như có các lớp tiện ích đọc để chỉ cần thực hiện ủy quyền tài khoản dịch vụ qua OAuth 2.0.

Tuy nhiên, tài liệu này không được nêu rõ, ngoại trừ tài liệu Google Drive chứa các giải thích và mẫu mã chi tiết bằng nhiều ngôn ngữ lập trình. Bạn nên đọc: https://developers.google.com/drive/service-accounts#google_apis_console_project_service_accounts

Một số vấn đề với mã của bạn:

  • ID của tài khoản dịch vụ phải ở trong các hình thức: <some-id>@developer.gserviceaccount.com (có email thay vì ID Client, tôi biết đó là lạ)
  • Bạn chỉ đặt principal khi thực hiện Google Apps domain Wide delegation nhưng bạn không thể thực hiện điều đó trên tài khoản Gmail, chỉ trên tài khoản Google Apps có miền bạn đã được quản trị viên cấp quyền truy cập. .

Dưới đây là mẫu mã cho OAuth 2.0 w/Tài khoản dịch vụ trong Java.

Lưu ý: Bạn cũng cần phải tải xuống 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

Vẫn nhận được ngoại lệ "invalid_grant" này khi làm việc với adsense. Id ứng dụng hợp lệ, phạm vi là AdSenseScopes.ADSENSE. API quản lý AdSense được kích hoạt. Không có đầu mối làm thế nào để sửa chữa nó – user12384512

+0

Rất hữu ích cho tôi ngay cả khi tôi làm việc với các wrapper NodeJS. Vấn đề của tôi là tôi đã sử dụng email tài khoản của mình thay vì địa chỉ email của ứng dụng. Cảm ơn! –

+0

Thật là một câu trả lời tuyệt vời! Tôi đã gặp lỗi JWT với api Java của Google Trang tính. Không có may mắn tìm giải pháp. Nó gần như không thể (ngoại trừ chủ đề này) để tìm một ví dụ mã Java đang hoạt động để nhận thông tin đăng nhập vào dịch vụ api của google thông qua Tài khoản dịch vụ.Khi tôi đổi thông tin đăng nhập của mình để phản ánh câu trả lời của bạn, tôi hiện có thể yêu cầu thành công đối với riêng tư qua API Google Trang tính. Ngoài ra, khi làm việc với trang tính, hãy đảm bảo bạn cho phép trong trang tính riêng tư (qua nút Chia sẻ) cho địa chỉ email của Tài khoản dịch vụ của bạn (trong tệp json/tệp nhận dạng đã tải xuống) – ganta