谷歌云存储:401 未经授权的错误

Posted

技术标签:

【中文标题】谷歌云存储:401 未经授权的错误【英文标题】:Google Cloud Storage: 401 unauthorized error 【发布时间】:2022-01-18 20:47:06 【问题描述】:

我的目标是将文件从 cloudhub 上传到 GCP 存储桶,我正在使用服务帐户,我唯一的选择是使用 Json Key 文件。

这就是我所做的:

    我已参考此 GCP information 和 this post 将文件上传到 GCP 云存储,我可以通过本地推送文件,但在 Cloudhub 中我无法将文件推送到存储桶。

我收到401 unauthorized error

在两个链接中都提到了在环境变量中设置GOOGLE_APPLICATION_CREDENTIALS = "path-to-json-key" 的步骤。

当我尝试在本地传递绝对路径 (/Users/..json-key) 时,它可以工作并且文件被上传到存储桶,但是当我在 cloudhub 运行时管理器中尝试传递 $app.home/"json-key"$mule.home/apps/$app.name/"json-key" 作为值时,它会失败。

该文件位于src/main/resources 目录中,我正在使用 java 类(如第二个链接中提到的调用静态)来上传文件。在这方面需要一些指导。

    我认为的另一种方法是,是否有可能以某种方式在 Java 类本身中使用这个 json 密钥文件,而不是通过环境变量传递它?

    如果以上两个选项都不起作用,还有其他方法可以在 cloudhub 中部署应用程序的服务帐户吗? (APIkey 是我尝试过的一种方法,但它并不将 APIKey 限制在特定的存储桶中)

Java 类

package com.mule.google.cloud.storage;

import com.google.cloud.storage.BlobId;
import com.google.cloud.storage.BlobInfo;
import com.google.cloud.storage.Storage;
import com.google.cloud.storage.StorageOptions;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import static java.nio.charset.StandardCharsets.UTF_8;

public class Upload 
    public static void uploadObject(String projectId, String bucketName, String objectName, String filePath)
            throws IOException 

        Storage storage = StorageOptions.newBuilder().setProjectId(projectId).build().getService();
        BlobId blobId = BlobId.of(bucketName, objectName);
        BlobInfo blobInfo = BlobInfo.newBuilder(blobId).build();
        storage.create(blobInfo, filePath.getBytes(UTF_8));
    

错误日志

Message               : Invocation of static Method 'uploadObject(java.lang.String,java.lang.String,java.lang.String,java.lang.String)' from Class 'com.mule.google.cloud.storage.Upload' with arguments [org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider arg0, org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider arg1, org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider arg2, org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider arg3] resulted in an error.
Expected arguments are [java.lang.String projectId, java.lang.String bucketName, java.lang.String objectName, java.lang.String filePath].
Cause: com.google.cloud.storage.StorageException - 401 Unauthorized
POST https://storage.googleapis.com/upload/storage/v1/b/"bucket-name"/o?projection=full&uploadType=multipart
Element               : upload-logFile/processors/3 @ poc-gcs-test:poc-mule-gcs.xml:305 (Invoke static)
Element DSL           : <java:invoke-static method="uploadObject(java.lang.String,java.lang.String,java.lang.String,java.lang.String)" doc:name="Invoke static" doc:id="3646e20f-0fef-4f57-84f8-d1ecc0f8afd5" class="com.mule.google.cloud.storage.Upload">
<java:args><![CDATA[
#[
    arg0: vars.projectId,
    arg1: vars.bucketName,
    arg2: vars.objectName,
    arg3: vars.agg_msg default [],
    
]
]]></java:args>
</java:invoke-static>
Error type            : JAVA:INVOCATION
FlowStack             : at upload-logFile(upload-logFile/processors/3 @ poc-gcs-test:poc-mule-gcs.xml:305 (Invoke static))
at consume-CustomerQ(consume-CustomerQ/processors/6 @ poc-gcs-test:poc-mule-gcs.xml:275 (Flow Reference upload-logFile))
Payload Type          : org.mule.runtime.core.internal.streaming.bytes.ManagedCursorStreamProvider
--------------------------------------------------------------------------------
Root Exception stack trace:
com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
POST https://storage.googleapis.com/upload/storage/v1/b/"bucket-name"/o?projection=full&uploadType=multipart

注意 - 问题似乎不是密钥文件通过环境错误传递。 java 类或任何包/依赖项无法通过具有该相对路径的环境访问它。

【问题讨论】:

【参考方案1】:

如果问题是文件无法在 CloudHub 中找到,请尝试使用此方法来引用它,如 KB article 中所述:

$mule.home/apps/$app.name/json-key

使用环境变量的方法在 CloudHub 上不起作用,因为无法通过设计来设置操作系统环境变量。您需要添加manual authentication code as described in GCP documentation。您可以在Java方法中添加一个参数来接收上述流程中计算的路径并使用它来加载Java中的密钥。

例子:

            var credential = GoogleCredential.FromFile(jsonPath);
            var storage = StorageClient.Create(credential);

请注意,您不应使用 System.out.println()。它不会扩展并且可能会导致问题。使用 Log4j2 记录器从 Java 代码记录。

【讨论】:

谢谢,我试过这种方法,但仍然会导致 401 错误。如果它是一个普通文件,我可以通过此属性或 app.home 读取它,但我认为问题在于传递给环境的密钥文件,java 类无法使用它。如果您注意到 java 类,那么在代码中的任何地方都没有使用密钥文件。任何包/依赖项仅使用环境中的密钥文件。 IDK 在工作室中如何工作,将绝对路径传递给密钥,但在 cloudhub 中不传递密钥的相对路径 环境变量方法在CloudHub上不起作用。您应该在代码中添加手动身份验证。更新我的答案。 感谢您将我引向正确的道路。这有帮助

以上是关于谷歌云存储:401 未经授权的错误的主要内容,如果未能解决你的问题,请参考以下文章

授权谷歌云平台服务账号只访问一个谷歌云存储桶

谷歌云函数抛出 404 错误

发布到 gitlab 工件时,401 未经授权从 maven

2017谷歌云大会,Google宣布了最新的云服务

使用 React 时,rails api-only 应用程序中出现 401 未经授权的错误

如何在谷歌大查询中从谷歌云存储上传表格