我正在用 Java 编写一个后端进程,它将模拟用户并在其 Google Drive 上添加/删除文档。
服务器帐户似乎验证正确,但是当我尝试冒充用户时,我得到一个401 Unauthorized error
。请参阅下面的详细信息。
配置
我已配置服务器帐户如下:
- 在Google API下创建了一个项目并启用了Google Drive API
- 创建了一个名为的服务帐户[电子邮件受保护] /cdn-cgi/l/email-protection,将角色设置为服务帐户参与者并为其赋予域范围的委派。它的客户端 ID 110xxxxxxxxx342
- 我已经下载了P12密钥文件
我已使用管理 API 客户端访问屏幕配置域以授权 110xxxxxxxxx342 具有范围:https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.
Google 支持人员查看了我的配置并竖起大拇指。
我的代码如下所示:
package com.dcm.sharingdocuments;
import java.io.File;
import java.io.IOException;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.Map.Entry;
import com.google.api.client.auth.oauth2.TokenErrorResponse;
import com.google.api.client.auth.oauth2.TokenResponseException;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.FileList;
public class SharingDocumentsTest3 {
private static final String SERVICE_ACCOUNT_EMAIL = " [email protected] /cdn-cgi/l/email-protection";
public static Drive getDriveService(String userEmail) throws Exception {
File keyFile = new File("E:\\Projects\\Workspace\\Sharing Documents\\authentication\\AnotherTestKeyFile.p12");
HttpTransport httpTransport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();
List<String> SCOPES = Arrays.asList(DriveScopes.DRIVE_METADATA_READONLY);
GoogleCredential credential = null;
if (userEmail == null) {
credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(keyFile).build();
credential.refreshToken();
} else {
credential = new GoogleCredential.Builder().setTransport(httpTransport).setJsonFactory(jsonFactory)
.setServiceAccountId(SERVICE_ACCOUNT_EMAIL).setServiceAccountScopes(SCOPES)
.setServiceAccountPrivateKeyFromP12File(keyFile).setServiceAccountUser(userEmail).build();
credential.refreshToken();
}
Drive service = new Drive.Builder(httpTransport, jsonFactory, null).setHttpRequestInitializer(credential)
.build();
return service;
}
public static void main(String[] args) {
SharingDocumentsTest3 sdt3 = new SharingDocumentsTest3();
sdt3.execute();
}
private void execute() {
try {
Drive service = getDriveService(null);
Drive services = getDriveService("[email protected] /cdn-cgi/l/email-protection");
displayFiles(services);
} catch (Exception e) {
e.printStackTrace();
}
}
private void displayFiles(Drive service) throws Exception {
FileList result = service.files().list().setPageSize(10).execute();
List<com.google.api.services.drive.model.File> files = result.getFiles();
if (files == null || files.size() == 0) {
System.out.println("No files found.");
} else {
System.out.println("Files:");
for (com.google.api.services.drive.model.File file : files) {
Set<Entry<String, Object>> entries = file.entrySet();
Iterator<Entry<String, Object>> it = entries.iterator();
while (it.hasNext()) {
Entry<String, Object> entry = it.next();
String key = entry.getKey();
Object value = entry.getValue();
if (value instanceof String) {
System.out.println("\tKey = " + key + ", Value = " + (String) value);
} else {
System.out.println("\tKey = " + key + ", Value = " + value.toString());
}
}
System.out.printf("%s (%s)\n", file.getName(), file.getId());
}
}
}
}
当我按上面的方式运行代码时,出现错误:
Mar 29, 2017 9:55:27 AM com.google.api.client.googleapis.services.AbstractGoogleClient <init>
WARNING: Application name is not set. Call Builder#setApplicationName.
com.google.api.client.auth.oauth2.TokenResponseException: 401 Unauthorized
at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:384)
at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
at com.dcm.sharingdocuments.SharingDocumentsTest3.getDriveService(SharingDocumentsTest3.java:50)
at com.dcm.sharingdocuments.SharingDocumentsTest3.execute(SharingDocumentsTest3.java:75)
at com.dcm.sharingdocuments.SharingDocumentsTest3.main(SharingDocumentsTest3.java:65)
因此,当我设置 setServiceAccountUser 时,代码在 credential.refreshToken() 处失败。它似乎已成功刷新令牌,而我却没有。我尝试过此代码的各种组合 - 例如注释掉了refreshToken()行,注释掉了getDriveService(null)行——但是每当我尝试使用/刷新为模拟用户获得的凭据时,我都会收到401未经授权的错误。
如果我修改代码,以便将 getDriveService(null) 获取的驱动器传递给 DisplayFiles(...),那么我会列出一个名为“入门”的文件。因此,服务帐户授权似乎正在运行,并且 Google 已将其默认文件添加到服务器帐户的云端硬盘中。
我在用google-*1.22.0.jar
文件和Java 1.8
运行上面的代码
我认为问题在于我配置域的方式或我尝试模拟用户的方式,但我的代码看起来与网络上的许多示例一样,并且 Google 支持似乎说我已正确配置域。
如果您能提出任何建议作为解决方案或下一步,我们将不胜感激!