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

Java使用服务账号认证Google Sheets API报错解决方案

问题根因

官方Java版快速入门的示例代码是为个人用户OAuth授权流程设计的,仅能解析OAuth客户端ID导出的凭证文件,和服务账号导出的JSON凭证结构完全不匹配。你遇到的IllegalArgumentException是代码尝试将服务账号凭证按OAuth客户端密钥格式解析时,字段校验失败直接抛出的,和表格权限、spreadsheetId配置无关——你之前做的这两项配置是正确的,问题核心是认证逻辑没有匹配服务账号的认证模式。

解决方案

依赖配置

首先确保引入最新版的官方认证依赖,不要使用已废弃的旧版认证类:

// Gradle 依赖示例
implementation 'com.google.auth:google-auth-library-oauth2-http:1.23.0'
implementation 'com.google.apis:google-api-services-sheets:v4-rev20240326-2.0.0'
implementation 'com.google.api-client:google-api-client:2.6.0'
implementation 'com.google.http-client:google-http-client-gson:1.44.1'

Maven用户可对应查找上述组件的最新稳定版坐标引入即可。

修正后的完整代码

直接替换原有类的全部逻辑,移除所有OAuth用户授权相关的代码(本地端口监听、本地token存储等逻辑对服务账号场景完全无用):

import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
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.services.sheets.v4.Sheets;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.ValueRange;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;

import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.util.Collections;
import java.util.List;

public class SheetsQuickstart {
    private static final String APPLICATION_NAME = "Google Sheets API Service Account Demo";
    private static final JsonFactory JSON_FACTORY = GsonFactory.getDefaultInstance();
    private static final String CREDENTIALS_FILE_PATH = "/credentials.json";
    // 按需调整权限范围,写操作替换为SheetsScopes.SPREADSHEETS即可
    private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS_READONLY);

    private static GoogleCredentials getServiceAccountCredentials() throws IOException {
        InputStream credentialStream = SheetsQuickstart.class.getResourceAsStream(CREDENTIALS_FILE_PATH);
        if (credentialStream == null) {
            throw new FileNotFoundException("Service account credential file missing: " + CREDENTIALS_FILE_PATH);
        }
        return GoogleCredentials.fromStream(credentialStream).createScoped(SCOPES);
    }

    public static void main(String... args) throws IOException, GeneralSecurityException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        final String spreadsheetId = "1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms";
        final String range = "Class Data!A2:E";

        Sheets sheetsService = new Sheets.Builder(
                httpTransport,
                JSON_FACTORY,
                // 用官方提供的适配器包装服务账号凭证
                new HttpCredentialsAdapter(getServiceAccountCredentials())
        ).setApplicationName(APPLICATION_NAME).build();

        ValueRange response = sheetsService.spreadsheets().values()
                .get(spreadsheetId, range)
                .execute();
        List<List<Object>> values = response.getValues();
        if (values == null || values.isEmpty()) {
            System.out.println("No data found.");
            return;
        }
        System.out.println("Name, Major");
        for (List<Object> row : values) {
            System.out.printf("%s, %s\n", row.get(0), row.get(4));
        }
    }
}
注意事项
  • 服务账号属于服务到服务的认证模式,不需要弹出浏览器让用户授权,也不需要本地监听8888端口、不需要在本地存储token缓存,原有代码里的相关逻辑可以全部删除。
  • 仅设置表格“持有链接的用户可编辑”对服务账号不生效,必须单独把目标表格的对应权限(读/写)授予服务账号JSON文件中client_email字段对应的邮箱地址,这一步你之前已经配置完成,不需要重复调整。
  • 上述代码全部使用当前官方推荐的非废弃API,没有使用已淘汰的GoogleCredential类,后续版本升级兼容性有保障。
  • 如果需要切换权限范围(比如从只读改为读写),直接修改SCOPES列表的取值即可,不需要重新下载服务账号凭证。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 17:36:28