为什么仅当我在 OpenShift 上部署时 Google Sheets API 才给我一个 invalid_scope 错误?
Why is Google Sheets API giving me an invalid_scope error only when I deploy on OpenShift?
我正在尝试从我的 Java 应用程序附加到现有的 Google Sheet,但我一直收到一条错误消息 "Empty or missing scope not allowed."
对我来说奇怪的是,当我将我的应用程序部署到 OpenShift 时才收到此错误。我在本地为 运行 相同的代码创建了一个测试用例,并且 Google Sheet 实际上已毫无问题地更新。
所以在我把这台笔记本电脑从建筑物的屋顶上扔下来之前,有人可以帮我看看我做错了什么吗?
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"
}
所以这实际上是我自己的愚蠢。我在这里发布答案,希望将来其他人会发现这个有用。
我忘记了 GoogleUtil 实际上是我们编写的一个实用程序 class,在我检查它之后,我意识到我的应用程序的部署版本正在从文件中读取信用,而测试正在读取信用来自 class 路径。当我从文件中读取时的代码没有添加范围,而从 class 路径读取的代码却添加了范围,因此我的结果看似奇怪。
这是错误的代码:
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;
}
}
我正在尝试从我的 Java 应用程序附加到现有的 Google Sheet,但我一直收到一条错误消息 "Empty or missing scope not allowed."
对我来说奇怪的是,当我将我的应用程序部署到 OpenShift 时才收到此错误。我在本地为 运行 相同的代码创建了一个测试用例,并且 Google Sheet 实际上已毫无问题地更新。
所以在我把这台笔记本电脑从建筑物的屋顶上扔下来之前,有人可以帮我看看我做错了什么吗?
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"
}
所以这实际上是我自己的愚蠢。我在这里发布答案,希望将来其他人会发现这个有用。
我忘记了 GoogleUtil 实际上是我们编写的一个实用程序 class,在我检查它之后,我意识到我的应用程序的部署版本正在从文件中读取信用,而测试正在读取信用来自 class 路径。当我从文件中读取时的代码没有添加范围,而从 class 路径读取的代码却添加了范围,因此我的结果看似奇怪。
这是错误的代码:
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;
}
}