You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过服务账号密钥文件为Google Drive API创建Credential凭证

Google Drive API服务账号鉴权问题及解决

问题描述

我正在使用Spring Boot和Java 8开发一个自动生成文件并上传至Google Drive的服务,该服务是另一个更大服务的外部模块。
我没有找到使用服务账号密钥为Google Drive API创建凭证的相关指引,因此参考官方身份认证文档自行编写了代码,功能是发起简单GET请求获取我Google Drive下的所有文件和文件夹,但运行时出现异常:
异常截图

原有问题代码

package com.example.demo.controller;

import com.example.demo.dto.FileItemDTO;
import com.example.demo.service.GoogleDriveService;
import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
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.gson.GsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.api.services.drive.model.File;
import com.google.api.services.drive.model.FileList;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.io.Resource;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

@RestController
public class GoogleDriveController {
    @Value("${google.service.account.key}")
    private static Resource serviceAccountKey;

    @Value("${external.address}")
    private String externalAddress;

    private final GoogleDriveService googleDriveService;
    private static HttpTransport HTTP_TRANSPORT = new NetHttpTransport();
    private static JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    private static final List<String> SCOPES = Collections.singletonList(DriveScopes.DRIVE_METADATA_READONLY);
    private static final String TOKENS_DIRECTORY_PATH = "tokens";

    @Autowired
    public GoogleDriveController(GoogleDriveService googleDriveService) throws IOException {
        this.googleDriveService = googleDriveService;
    }

    private static Credential getCredentials(final NetHttpTransport HTTP_TRANSPORT) throws IOException {
        // Load client secrets.
        java.io.File file = new java.io.File("path-to-credential-file");
        InputStream inputStream = new FileInputStream(file);
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(inputStream));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(new FileDataStoreFactory(new java.io.File(TOKENS_DIRECTORY_PATH)))
                .setAccessType("offline")
                .build();
        LocalServerReceiver receiver = new LocalServerReceiver.Builder().setPort(8868).build();

        return new AuthorizationCodeInstalledApp(flow, receiver).authorize("user");
    }

    @GetMapping(value = {"/static-page/get"})
    public @ResponseBody
    List<FileItemDTO> getStaticPage() throws Exception {
        String pageToken = null;

        final NetHttpTransport HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();

        Drive drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, getCredentials(HTTP_TRANSPORT)).build();
        List<FileItemDTO> responseList = new ArrayList<>();

        FileList fileList = drive.files().list().setFields("files(id,name,thumbnailLink)").execute();
        for (File file : fileList.getFiles()) {
            FileItemDTO item = new FileItemDTO();
            item.setId(file.getId());
            item.setName(file.getName());
            item.setThumbnailLink(file.getThumbnailLink());
            responseList.add(item);
        }

        return responseList;
    }
}

该服务账号已被授予所有者角色,据我了解拥有所有者角色的服务账号密钥具备最高权限。

修复方案

删除原有getCredentials()方法,改用服务账号凭证类直接构造鉴权初始化器,修改后的Drive对象创建代码如下,目前运行正常:

// file 1 为JSON格式的凭证文件
// GoogleCredential 已弃用,因此改用 HttpRequestInitializer
HttpRequestInitializer requestInitializer = new HttpCredentialsAdapter(ServiceAccountCredentials.fromStream(new FileInputStream(file1))
        .createScoped(DriveScopes.all()));
Drive drive = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, requestInitializer)
        .setApplicationName(ApplicationName).build();

内容的提问来源于stack exchange,提问作者Dattq2303

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 18:06:08