0

全部

我尝试了使用服务帐户的 Gmail API。我实现了以下代码:

package mywork.gmail.api;

import java.io.File;
import java.io.IOException;
import java.security.GeneralSecurityException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.gmail.Gmail;
import com.google.api.services.gmail.GmailScopes;
import com.google.api.services.gmail.model.ListMessagesResponse;
import com.google.api.services.gmail.model.Message;

public class GmailApi {
    /** 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 = "src/main/resources/*******-privatekey.p12";

    public static void main(String[] args) throws Exception {
        GmailApi app = new GmailApi();

        String userId = "****@example.com";
        String labelId = "INBOX";

        app.listMessage(userId, labelId);
    }

    public void listMessage(String userId, String labelId) throws Exception {
        Gmail service = initService(userId);

        ListMessagesResponse response = service.users().messages().list(userId)
                .setLabelIds(Arrays.asList(labelId)).execute();

        List<Message> messages = new ArrayList<Message>();
        while (response.getMessages() != null) {
            messages.addAll(response.getMessages());
            if (response.getNextPageToken() != null) {
                String pageToken = response.getNextPageToken();
                response = service.users().messages().list(userId)
                        .setPageToken(pageToken).execute();
            } else {
                break;
            }
        }

        for (Message message : messages) {
            System.out.println(message.toPrettyString());
        }
    }

    private Gmail initService(String userId) throws GeneralSecurityException,
            IOException {

        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        JacksonFactory jsonFactory = JacksonFactory.getDefaultInstance();
        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(jsonFactory)
                .setServiceAccountId(SERVICE_ACCOUNT_EMAIL)
                .setServiceAccountScopes(Arrays.asList(GmailScopes.MAIL_GOOGLE_COM))
                .setServiceAccountUser(userId)
                .setServiceAccountPrivateKeyFromP12File(new File(SERVICE_ACCOUNT_PKCS12_FILE_PATH))
                .build();

        Gmail service = new Gmail.Builder(httpTransport, jsonFactory, credential)
                .setApplicationName("Gmail API sample").build();

        return service;
    }
}

但该代码返回 403 错误:

Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 403 Forbidden
    {
      "error" : "access_denied",
      "error_description" : "Requested client not authorized."
    }

当然,我通过 Google Developer Console 启用了 Gmail API,并通过管理控制台设置了权限(包括 Gmail 范围)。

怎么了?

谢谢!

4

1 回答 1

2

如果您的应用程序访问用户数据,您创建的服务帐户需要被授予访问您想要访问的 Google Apps 域的用户数据的权限。

以下步骤必须由 Google Apps 域的管理员执行: 转到您的 Google Apps 域的管理控制台。

从控件列表中选择安全性。如果您没有看到列出的安全性,请从页面底部的灰色栏中选择更多控件,然后从控件列表中选择安全性。

从选项列表中选择高级设置。

在身份验证部分中选择管理第三方 OAuth 客户端访问。

在客户端名称字段中输入服务帐户的客户端 ID。

在一个或多个 API 范围字段中,输入应授予您的应用程序访问权限的范围列表。例如,如果您需要在域范围内访问 Google Drive API 和 Google Calendar API,请输入:https://www.googleapis.com/auth/drivehttps://www.googleapis.com/auth/calendar

单击授权。

另外,请检查您的代码中是否包含应用程序尝试访问的所有范围。

如果您仍然看到问题,请告诉我。

于 2014-11-20T19:55:30.043 回答