我使用 @aws-sdk/client-s3 库创建预签名 URL,然后使用此 URL 将文件上传到 S3。在生成预签名 URL 时,我使用 Key 属性,其中包括文件名和内容类型。
但是,问题是当我使用预签名 URL 上传文件时,它允许我上传任何文件。我想要做的是,如果文件名和内容类型与我用于生成预签名 URL 的文件名和内容类型不匹配,则限制文件上传。
以下是代码:
async getUploadPreSignedUrl(key, bucket, expiresInSeconds = 1800)
{
try {
const contentType = mime.lookup(key) || undefined;
if (!contentType) {
throw new Error('Invalid Content Type')
}
const params = { Bucket: bucket, Key: key, ContentType: contentType, };
const putObjectCommand = new PutObjectCommand(params);
console.log(params, putObjectCommand)
const signedUrl = await getSignedUrl(this.s3, putObjectCommand,
{ expiresIn: expiresInSeconds, });
return signedUrl;
}
catch (error) {
console.error("Error generating upload pre-signed URL:", error); throw error; }
}
我想要的是,如果我们使用不同的文件名或不同的内容类型,上传应该返回错误。
为了确保签名的 URL 仅适用于上传其创建的文件,您必须在
conditions
中设置 getUploadPreSignedUrl
。 CreatePresignedPostCommand
库中有一个 @aws-sdk/client-s3
方法可以帮助解决此问题。我刚刚使用该方法重写了您的 getUploadPreSignedUrl
并合并了检查 conditions
:
const { S3Client, CreatePresignedPostCommand } = require('@aws-sdk/client-s3');
async getUploadPreSignedUrl(key, bucket, expiresInSeconds = 1800) {
try {
const contentType = mime.lookup(key) || undefined;
if (!contentType) {
throw new Error('Invalid Content Type');
}
// This is where you set the conditions, eq checks for equality
const conditions = [
{ bucket: bucket },
['eq', '$key', key],
['eq', '$Content-Type', contentType]
];
const params = {
Bucket: bucket,
Key: key,
Conditions: conditions,
Expires: expiresInSeconds,
};
// Generate the presigned post URL using CreatePresignedPostCommand
const command = new CreatePresignedPostCommand(params);
const { url, fields } = await this.s3.send(command);
return { url, fields };
} catch (error) {
console.error("Error generating upload pre-signed URL:", error);
throw error;
}
}
如果使用此signedUrl上传任何其他文件(不同的
contentType
或name
),则会抛出403 Forbidden错误。
为了在前端使用此上传方法,我添加了一个使用浏览器
fetch
API 的示例。
async function uploadFileToBucket(file, presignedUrlData) {
const formData = new FormData();
// Append fields from presignedUrlData.fields
Object.entries(presignedUrlData.fields).forEach(([key, value]) => {
formData.append(key, value);
});
// Append the file content here
formData.append('file', file);
// This uploads to the S3 bucket
try {
const response = await fetch(presignedUrlData.url, {
method: 'POST',
body: formData,
});
if (!response.ok) {
throw new Error(`Upload failed with status: ${response.status}`);
}
console.log("Your file uploaded successfully!");
} catch (error) {
console.error("Error uploading file:", error);
}
}
我想这应该可以解决你的问题