Как загрузить файлы в папку на Google Team Drive с учетными данными учетной записи службы? - PullRequest
2 голосов
/ 13 июня 2019

Я пытаюсь внедрить новый сервис для нашего приложения, используя Google Drive Java API v3, который отвечает за загрузку файлов в определенную папку в Google Team Drive.Я использую служебную учетную запись, созданную моей компанией специально для этого проекта, а также сгенерировал файл JSON из Google Developer Console, который содержит закрытый ключ.Я также поделился этой папкой с учетной записью службы, используя ее электронную почту xxxxx@xxxx.iam.gserviceaccount.com, и предоставил права Content Manager на общий Team Drive.Кроме того, полномочия G Suite на уровне домена не были предоставлены этой учетной записи службы по нескольким причинам.

Чего я здесь пытаюсь достичь: Я хочу создать и вернуть авторизованный клиентский сервис Google Диска, используя сгенерированный закрытый ключ аккаунта сервиса, и поэтому могу отправлять запросы на загрузку файлов в папку в Google Team Drive.

То, что я в данный моментПрименение:

  • IntelliJ IDEA IntelliJ IDEA 2018.1.7 (Ultimate Edition)
  • Spring Boot 2
  • Java 10.0.1

В чем проблема: Я не могу вернуть авторизованный клиентский сервис Google Диска, и запросы на загрузку файлов вообще не отправляются.Что делает его еще более запутанным, так это то, что нет исключений.Тем не менее, учетные данные возвращаются успешно с токеном доступа и сроком действия.

То, что я уже прочитал / нашел: Использование OAuth2.0 для приложения «сервер-сервер»: https://developers.google.com/identity/protocols/OAuth2ServiceAccount

Быстрый запуск Java при создании простых запросов к API привода: https://developers.google.com/drive/api/v3/quickstart/java

Справочник по JavaDoc для API привода: https://developers.google.com/resources/api-libraries/documentation/drive/v3/java/latest/

Как загрузить файл на диск Google с учетными данными учетной записи службы: Как загрузить файл на диск Google с учетными данными учетной записи службы

Как получить доступ к Team Drive с помощью учетной записи службы в GoogleDrive .NET API v3: Как получить доступ к Team Drive с помощью служебной учетной записи с помощью Google Drive .NET API v3

Аутентификация для загрузки файлов на мой диск с помощью клиентской библиотеки API Google Drive для Java Аутентификация для загрузки файлов на мой диск с использованием клиентской библиотеки API Google drive для Java

Что я уже пробовал:

  • Использование GoogleCredential-класса для возврата учетных данных (этот класс устарел: https://googleapis.dev/java/google-api-client/latest/)
  • Поиск замены для устаревшего класса путем изучения проектов и учебных пособий Github
  • Обновите и проверьте все отсутствующие зависимости в pom.xml
  • Проверены настройки общего Team Drive, чтобы убедиться, что он используется совместно с учетной записью службы.
  • Добавлены логи, чтобы убедиться, что проблема действительно та, что я описал выше
  • Пробовал Java Quickstart при создании простых запросов к учебнику по API Drive (однако, это оказалось не совсем подходящим для потребностей нашего проекта)

Соответствующая часть ContractStateUpdateService.java:

File fileMetadata = new File();
fileMetadata.setName(fileTitle);
// setting the id of folder to which the file must be inserted to
fileMetadata.setParents(Collections.singletonList("dumbFolderId"));
fileMetadata.setMimeType("application/pdf");

byte[] pdfBytes = Base64.getDecoder().decode(base64File.getBytes(StandardCharsets.UTF_8));
InputStream inputStream = new ByteArrayInputStream(pdfBytes);

// decoding base64 to PDF and its contents to a byte array without saving the file on the file system
InputStreamContent mediaContent = new InputStreamContent("application/pdf", inputStream);

logger.info("Starting to send the request to drive api");
File file = DriveUtils.getDriveService().files().create(fileMetadata, mediaContent).execute();
logger.info("Succesfully uploaded file: " + file.getDriveId());

DriveUtils.java:

public class DriveUtils {

    private static final String APPLICATION_NAME = "Google Drive Service";

    // setting the Drive scope since it is essential to access Team Drive
    private static List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE);

    // private key is stored at the root of the project for now
    private static String PRIVATE_KEY_PATH = "/path/to/private_key.json";
    private static final Logger logger = LoggerFactory.getLogger(DriveUtils.class);

    // build and return an authorized drive client service
    public static Drive getDriveService() throws IOException, GeneralSecurityException {
        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        GoogleCredentials credentials;

        try (FileInputStream inputStream = new FileInputStream(PRIVATE_KEY_PATH)){
            credentials = ServiceAccountCredentials.fromStream(inputStream).createScoped(SCOPES);
            credentials.refreshIfExpired();
            AccessToken token = credentials.getAccessToken();
            logger.info("credentials: " + token.getTokenValue());
        } catch (FileNotFoundException ex) {
            logger.error("File not found: {}", PRIVATE_KEY_PATH);
            throw new FileNotFoundException("File not found: " + ex.getMessage());
        }

        logger.info("Instantiating client next");
        // Instantiating a client: this is where the client should be built but nothing happens... no exceptions!
        Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, (HttpRequestInitializer) credentials)
                .setApplicationName(APPLICATION_NAME)
                .build();
        // this log should appear immediately after the client has been instantiated but still nothing happens
        logger.info("Client instantiated");

        return service;
    }

}

pom.xml:

<!-- https://mvnrepository.com/artifact/com.google.api-client/google-api-client -->
        <dependency>
            <groupId>com.google.api-client</groupId>
            <artifactId>google-api-client</artifactId>
            <version>1.29.2</version>
        </dependency>

        <dependency>
            <groupId>com.google.apis</groupId>
            <artifactId>google-api-services-drive</artifactId>
            <version>v3-rev165-1.25.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.auth/google-auth-library-oauth2-http -->
        <dependency>
            <groupId>com.google.auth</groupId>
            <artifactId>google-auth-library-oauth2-http</artifactId>
            <version>0.16.1</version>
        </dependency>


        <!-- https://mvnrepository.com/artifact/org.springframework.security.oauth/spring-security-oauth2 -->
        <dependency>
            <groupId>org.springframework.security.oauth</groupId>
            <artifactId>spring-security-oauth2</artifactId>
            <version>2.3.6.RELEASE</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.oauth-client/google-oauth-client-jetty -->
        <dependency>
            <groupId>com.google.oauth-client</groupId>
            <artifactId>google-oauth-client-jetty</artifactId>
            <version>1.29.0</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/com.google.code.gson/gson -->
        <dependency>
            <groupId>com.google.code.gson</groupId>
            <artifactId>gson</artifactId>
            <version>2.8.5</version>
        </dependency>

Я уверен, что чего-то здесь не хватает, и заранее прошу прощения за мой английский.Любая помощь будет оценена.

1 Ответ

0 голосов
/ 05 июля 2019

Спасибо за ваши комментарии, советы здесь были полезны и заслуживали изучения. Однако решение, которое я собираюсь представить здесь, не будет отвечать на мой вопрос непосредственно о том, как или почему мой код не выдал никаких сообщений об ошибках. Итак, на данный момент, это мой обходной путь решения проблемы:

  1. Включение Drive API. После прочтения значительной части статей и документации по выполнению запросов от служебной учетной записи к Drive API стало ясно, что мой код не будет работать, если у нас не было Drive API включен из Google API Console.
  2. Понижение версии трех зависимостей до 1.23.0.

pom.xml:

 <dependency>
    <groupId>com.google.api-client</groupId>
    <artifactId>google-api-client</artifactId>
    <version>1.23.0</version>
 </dependency>
 <dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-drive</artifactId>
    <version>v3-rev110-1.23.0</version>
 </dependency>
 <dependency>
    <groupId>com.google.oauth-client</groupId>
    <artifactId>google-oauth-client-jetty</artifactId>
    <version>1.23.0</version>
 </dependency>
  1. Установка значения свойства setSupportsTeamDrive в значение true. Без свойства мы бы вообще не смогли сохранить файлы в общей папке в Team Drive.

ContractStateUpdateService.java:

File fileMetadata = new File();
fileMetadata.setName(fileTitle);

// setting the id of folder to which the file must be inserted to
fileMetadata.setParents(Collections.singletonList("dumbTeamDriveId"));
fileMetadata.setMimeType("application/pdf");

// decoding base64 to PDF and its contents to a byte array without saving the file on the file system
byte[] pdfBytes = Base64.getDecoder().decode(base64File.getBytes(StandardCharsets.UTF_8);
InputStream inputStream = new ByteArrayInputStream(pdfBytes);
InputStreamContent mediaContent = new InputStreamContent("application/pdf", inputStream);

try {
  // upload updated agreement as a PDF file to the Team Drive folder
  DriveUtils.getDriveService().files().create(fileMetadata, mediaContent)
                            .setSupportsTeamDrives(true) // remember to set this property to true!
                            .execute();
} catch (IOException ex) {
  logger.error("Exception: {}", ex.getMessage());
  throw new IOException("Exception: " + ex.getMessage());
} catch (GeneralSecurityException ex) {
  logger.error("Exception: {}", ex.getMessage());
  throw new GeneralSecurityException("Exception: " + ex.getMessage());
}
  1. Разделение метода, чтобы сделать логику более понятной.

Обновлен код с DriveUtils-class :

// create and return credential
private static Credential getCredentials() throws IOException {
    GoogleCredential credential = GoogleCredential.fromStream(new FileInputStream(PRIVATE_KEY_PATH))
                .createScoped(SCOPES);

    return credential;
}

// build and return an authorized drive client service
public static Drive getDriveService() throws IOException, GeneralSecurityException {
    final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

    // Instantiating a client
    Drive service = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials())
                .setApplicationName(APPLICATION_NAME)
                .build();

    return service;
}
...