为什么只有在OpenShift上部署时,Google Sheets API才会给我invalid_scope错误?

时间:2018-07-17 18:51:13

标签: java google-api google-sheets-api google-api-java-client

我试图从我的Java应用程序追加到现有的Google表格中,但不断收到错误消息,提示“不允许为空或缺少作用域”。

对我来说奇怪的是,当我将应用程序部署到OpenShift时仅收到此错误时。我创建了一个测试用例,以在本地运行相同的代码,并且Google表格实际上已更新,没有问题。

所以在我将笔记本电脑从建筑物的屋顶上扔掉之前,有人可以帮我看看我做错了什么吗

public class SpreadsheetClient {
    private static final Logger LOG = LoggerFactory.getLogger(SpreadsheetClient.class);
    private static final List<String> SCOPES = Collections.singletonList(SheetsScopes.SPREADSHEETS);
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
    private static final String APPLICATION_NAME = "My App";
    private static final String START_RANGE = "A2";
    private static final String VALUE_INPUT_OPTION = "RAW";
    private static final String INSERT_DATA_OPTION = "INSERT_ROWS";


    private Sheets sheets;

    public SpreadsheetClient(String certPath) throws GeneralSecurityException, IOException {
        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
        sheets = new Sheets.Builder(httpTransport, JSON_FACTORY, GoogleUtil.getGoogleCredential(certPath, SCOPES))
                .setApplicationName(APPLICATION_NAME).build();
    }

    public void appendRows(String sheetId, List<List<Object>> values, Handler<AsyncResult<Void>> handler) {
        try {
            AppendValuesResponse response = sheets.spreadsheets().values().append(sheetId, START_RANGE, new ValueRange().setValues(values))
                    .setValueInputOption(VALUE_INPUT_OPTION)
                    .setInsertDataOption(INSERT_DATA_OPTION)
                    .execute();

            if (response.getUpdates().getUpdatedRows() == values.size()) {
                handler.handle(Future.succeededFuture());
            }
            else {
                LOG.error("Expected to update {} rows, updated {} instead", values.size(), response.getUpdates().getUpdatedRows());
                JsonArray updateValues = new JsonArray(response.getUpdates().getUpdatedData().getValues());
                LOG.debug("The update values are {}", updateValues);
                handler.handle(ServiceException.fail(NOT_ENOUGH_ROWS_UPDATED.code(), updateValues.encode()));
            }
        }
        catch (IOException ex) {
            LOG.error("Failed to append to spreadsheet", ex);
            handler.handle(Future.failedFuture(ex));
        }
    }
}

这是我的凭证文件(显然剥去了真实的凭证):

{
  "type": "service_account",
  "project_id": "account",
  "private_key_id": "an_id",
  "private_key": "-----BEGIN PRIVATE KEY-----\nstuff\n-----END PRIVATE KEY-----\n",
  "client_email": "service@account.iam.gserviceaccount.com",
  "client_id": "another_id",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://accounts.google.com/o/oauth2/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/service%40account.iam.gserviceaccount.com"
}

1 个答案:

答案 0 :(得分:0)

这实际上是我自己的愚蠢。我将答案发布在这里,以便希望其他人将来会发现它有用。

我忘记了GoogleUtil实际上是我们编写的实用程序类,一旦检查了它,就意识到应用程序的部署版本正在从文件中读取凭据,而测试是从类路径中读取凭据。当我从文件读取时,代码没有添加作用域,而从类路径中读取的代码却添加了作用域,因此,我的结果似乎很奇怪。

这是错误的代码:

public class GoogleUtil {
    private static final Logger LOG = LoggerFactory.getLogger(GoogleUtil.class);

    private GoogleUtil() {}

    public static GoogleCredential getGoogleCredential(String certPath, List<String> scopes) {
        GoogleCredential googleCredential;
        try {
            googleCredential = GoogleCredential.fromStream(new FileInputStream(certPath));
        }
        catch (IOException ioe) {
            try {
                LOG.info("The certificate file {} was not found, trying to find it in the class path", certPath);
                googleCredential = GoogleCredential.fromStream(DriveClient.class.getResourceAsStream("/google-ambassador-service-account.json")).createScoped(scopes);
            }
            catch (IOException ex) {
                LOG.error("Could not find the file {}", certPath);
                googleCredential = new GoogleCredential();
            }
        }

        return googleCredential;
    }
}

我的解决方法:

public class GoogleUtil {
    private static final Logger LOG = LoggerFactory.getLogger(GoogleUtil.class);

    private GoogleUtil() {}

    public static GoogleCredential getGoogleCredential(String certPath, List<String> scopes) {
        GoogleCredential googleCredential;
        try {
            googleCredential = GoogleCredential.fromStream(new FileInputStream(certPath)).createScoped(scopes);
        }
        catch (IOException ioe) {
            LOG.error("Could not find the file {}", certPath);
            googleCredential = new GoogleCredential();
        }

        return googleCredential;
    }
}