英文:
Uploading file to Google Storage with signed Url
问题
I'm trying to upload a file directly from the frontend to Google Storage. I'm working on a hydrogen environment (similar to cloudflare) so I can't use normal google libraries in the backend.
Whenever I try to upload one file I get the following problem:
My frontend code:
export const uploadFile = async (file: File, signedUrl: string) => {
const response = await axios.put(signedUrl, file, {
headers: {
'Content-Type': file.type,
},
});
return response;
};
My backend code:
export const getSignedUrl = async (
bucketName: string,
privateKey: string,
accountEmail: string,
) => {
const expiration = Math.floor(Date.now() / 1000) + 60 * 60; // 1 hour from now
const objectName = uuidv4();
// Construct the canonical resource.
const canonicalResource = `/${bucketName}/${objectName}`;
// Construct the string to sign.
const stringToSign =
`PUT\n` + // HTTP verb
`\n` + // Content-MD5 (empty)
`image/png\n` + // Content-Type
`${expiration}\n` + // Expires
`${canonicalResource}`; // CanonicalizedResource
const secret = base64Decode(privateKey);
const textEncoder = new TextEncoder();
const secretUint8Array = textEncoder.encode(secret);
const key = await crypto.subtle.importKey(
'raw',
secretUint8Array,
{name: 'HMAC', hash: 'SHA-256'},
false,
['sign'],
);
const stringToSignUint8Array = textEncoder.encode(stringToSign);
const signatureUint8Array = await crypto.subtle.sign(
'HMAC',
key,
stringToSignUint8Array,
);
const signature = base64Encode(signatureUint8Array);
// Finally, you can construct the signed URL.
const signedUrl =
`https://storage.googleapis.com/${bucketName}/${objectName}` +
`?GoogleAccessId=${accountEmail}` +
`&Expires=${expiration}` +
`&Signature=${encodeURIComponent(signature)}`;
return signedUrl;
};
What am I doing wrong?
英文:
I'm trying to upload a file directly from the frontend to Google Storage. I'm working on hydrogen environment (similar to cloudflare) so I can't use normal google libraries in the backend.
Whenever I try to upload one file I get the following problem:
<?xml version='1.0' encoding='UTF-8'?><Error><Code>SignatureDoesNotMatch</Code><Message>The request signature we calculated does not match the signature you provided. Check your Google secret key and signing method.</Message><StringToSign>PUT
image/png
1684774590
/BUCKET_NAME/92f3f1ab-1272-4ad8-acb7-b89c06523641</StringToSign></Error>
My frontend code:
export const uploadFile = async (file: File, signedUrl: string) => {
const response = await axios.put(signedUrl, file, {
headers: {
'Content-Type': file.type,
},
});
return response;
};
My backend code:
export const getSignedUrl = async (
bucketName: string,
privateKey: string,
accountEmail: string,
) => {
const expiration = Math.floor(Date.now() / 1000) + 60 * 60; // 1 hour from now
const objectName = uuidv4();
// Construct the canonical resource.
const canonicalResource = `/${bucketName}/${objectName}`;
// Construct the string to sign.
const stringToSign =
`PUT\n` + // HTTP verb
`\n` + // Content-MD5 (empty)
`image/png\n` + // Content-Type
`${expiration}\n` + // Expires
`${canonicalResource}`; // CanonicalizedResource
const secret = base64Decode(privateKey);
const textEncoder = new TextEncoder();
const secretUint8Array = textEncoder.encode(secret);
const key = await crypto.subtle.importKey(
'raw',
secretUint8Array,
{name: 'HMAC', hash: 'SHA-256'},
false,
['sign'],
);
const stringToSignUint8Array = textEncoder.encode(stringToSign);
const signatureUint8Array = await crypto.subtle.sign(
'HMAC',
key,
stringToSignUint8Array,
);
const signature = base64Encode(signatureUint8Array);
// Finally, you can construct the signed URL.
const signedUrl =
`https://storage.googleapis.com/${bucketName}/${objectName}` +
`?GoogleAccessId=${accountEmail}` +
`&Expires=${expiration}` +
`&Signature=${encodeURIComponent(signature)}`;
return signedUrl;
};
What am I doing wrong?
答案1
得分: 1
当请求中计算的签名与给定的签名不匹配时,将返回“SignatureDoesNotMatch”错误。
- 检查
bucketName
和objectName
的一致性,以及前端和后端创建的stringToSign
。 - 检查用于私钥的
base64Encode
和base64Decode
函数是否正常工作。 - 验证是否需要在签名中使用
encodeURIComponent
。 - 确保前端和后端使用的散列和签名算法是相同的。
- 确保后端正确使用
crypto.subtle.importKey
导入私钥。 - 为了查找任何不一致之处,比较前端生成的签名与后端计算的签名。
您可以查看这篇谷歌文档有关签名 URL的文档。
英文:
When the calculated signature in the request does not match the signature given, the "SignatureDoesNotMatch" error is returned.
- Check the consistency of
bucketName
andobjectName
as well as thestringToSign
created on the frontend and backend. - Check that the
base64Encode
andbase64Decode
functions for the private key are functioning properly. - Verify whether it's essential to use
encodeURIComponent
for the signature in the signed URL. - Verify that the hashing and signing algorithms used by the frontend and the backend are identical.
- Make that the backend uses
crypto.subtle.importKey
to import the private key properly. - To find any inconsistencies, compare the signature generated on the frontend with the one computed on the backend.
You may check this Google documentation about Signed URLs.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论