Uploading file to Google Storage with signed Url

huangapple go评论63阅读模式
英文:

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”错误。

  1. 检查bucketNameobjectName的一致性,以及前端和后端创建的stringToSign
  2. 检查用于私钥的base64Encodebase64Decode函数是否正常工作。
  3. 验证是否需要在签名中使用encodeURIComponent
  4. 确保前端和后端使用的散列和签名算法是相同的。
  5. 确保后端正确使用crypto.subtle.importKey导入私钥。
  6. 为了查找任何不一致之处,比较前端生成的签名与后端计算的签名。

您可以查看这篇谷歌文档有关签名 URL的文档。

英文:

When the calculated signature in the request does not match the signature given, the "SignatureDoesNotMatch" error is returned.

  1. Check the consistency of bucketName and objectName as well as the stringToSign created on the frontend and backend.
  2. Check that the base64Encode and base64Decode functions for the private key are functioning properly.
  3. Verify whether it's essential to use encodeURIComponent for the signature in the signed URL.
  4. Verify that the hashing and signing algorithms used by the frontend and the backend are identical.
  5. Make that the backend uses crypto.subtle.importKey to import the private key properly.
  6. 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.

huangapple
  • 本文由 发表于 2023年5月23日 00:21:04
  • 转载请务必保留本文链接:https://go.coder-hub.com/76308167.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定