尝试允许客户端通过预签名的 URL 上传文件时遇到问题。
收到错误
<?xml version='1.0' encoding='UTF-8'?>
<Error>
<Code>AccessDenied</Code>
<Message>Access denied.</Message>
<Details>
urlsigner@<project>.iam.gserviceaccount.com does not have storage.objects.create access to <bucket-name>/<filename>.pdf.
</Details>
</Error>
代码作为 gcp 云函数执行,用于生成。云函数是默认的服务帐户函数,已更新为 urlSigner
async createSignedUrl({
contentType,
fileName,
userId,
}: SignedUrlRequest): Promise<string> {
const bucket = await this.cloudStorage.bucket(BUCKET_NAME);
console.log(
moment.utc().add('minutes', 15).toDate(),
Date.now() + 15 * 60 * 1000
);
const options: any = {
version: 'v4',
action: 'write',
expires: Date.now() + 15 * 60 * 1000,
contentType,
};
const [signedUrl] = await bucket
.file(`${userId}-${fileName}`)
.getSignedUrl(options);
return signedUrl;
}
CORS 临时 json 文件
[
{
"maxAgeSeconds": 3600,
"method": ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
"origin": ["*"],
"responseHeader": [
"Content-Type",
"Authorization",
"Content-Length",
"User-Agent",
"x-goog-resumable"
]
}
]
创建 GCP 资源的步骤
gcloud iam service-accounts create urlsigner --display-name="GCS URL Signer" --project=<project-id>
gcloud iam service-accounts keys create service_account.json --iam-account=urlsigner@<project-id>.iam.gserviceaccount.com
gsutil mb gs://<bucket-name>
gsutil iam ch serviceAccount:urlsigner@<project-id>.iam.gserviceaccount.com:roles/storage.admin gs://<bucket-name>
gsutil cors set cors-json-file.json gs://<bucket-name>
上传代码
export async function uploadDoc(preSignedUrl: string, file: File) {
return await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.open('PUT', preSignedUrl, true);
xhr.onload = () => {
const status = xhr.status;
if (status === 200) {
console.log('uploaded');
resolve('good to go');
} else {
console.log('failed to upload');
reject('not good to go');
}
};
xhr.onabort = () => {
reject('aborted for idk');
};
xhr.onerror = () => {
reject('Failed for idk');
};
xhr.setRequestHeader('Content-Type', file.type);
const formData = new FormData();
formData.append('verify-doc', file);
xhr.send(formData);
});
}
最后,验证云函数是否具有对发送回前端的 blob 进行签名所需的 Service-Token-Creator 角色,以及在存储桶权限下,服务帐户是否也列出了存储管理员角色。所以现在我只是在挠头,为什么我会收到由于服务帐户缺乏权限而被拒绝访问的错误。
在此先向所有能提供帮助的人表示感谢。