通过后端预签署的 Policy 在前端直接与 Amazon S3 交互并上传文件 AWS SDK for JavaScript v3 阿里云 OSS
tags:
- 基础设施/云服务商/亚马逊云
- 基础设施/云服务商/亚马逊云/AWS
- 基础设施/存储/对象存储/亚马逊云/AWS/S3
- 开发/后端
- 开发/前端
- 计算机/信息技术/安全
- 开发/Nodejs
- 开发/Nodejs/pnpm
通过后端预签署的 Policy 在前端直接与 Amazon S3 交互并上传文件
这种技术也被称之为「服务端签名直传」、「客户端直传」、「Web 端直传」、「前端直传」,在阿里云 OSS 中也有支持1。
通过后端预签署的 Policy 在前端直接与 Amazon S3 或阿里云 OSS 交互并上传文件的技术,通常被称为“服务端签名直传”或“客户端直传”。这种技术允许用户直接在前端浏览器或客户端应用中上传文件到云存储服务,而无需先将文件发送到后端服务器。这不仅提高了上传速度,还减轻了后端服务器的负担。
以下是这种技术的基本步骤:
后端生成预签名策略:
后端服务器根据业务需求生成一个预签名的策略(Policy)。这个策略定义了哪些文件可以上传、上传到哪里、文件的存储类型等。
后端使用 AWS 或阿里云提供的 SDK,结合自身的访问密钥(Access Key 和 Secret Key),对这个策略进行签名,生成一个签名值。
前端获取预签名策略:
前端应用(如网页或移动应用)通过 API 请求从后端服务器获取这个预签名的策略和签名值。
前端直传文件到云存储:
用户在前端选择文件后,前端应用使用之前从后端获取的预签名策略和签名值,构造一个上传请求。
这个上传请求直接发送到 Amazon S3 或阿里云 OSS,而不需要经过后端服务器。
云存储服务验证请求的签名和策略,如果一切正常,就会接受文件并存储。
上传完成和回调:
文件上传完成后,云存储服务可能会发送一个回调通知到后端服务器,告知文件已经成功上传。
后端服务器可以根据这个通知执行后续操作,如更新数据库中的文件信息。
这种技术的优点包括:
提高上传速度:文件直接从客户端上传到云存储,避免了后端服务器的中转,从而提高了上传速度。
减轻后端负担:后端服务器不再需要处理大量的文件上传请求,可以专注于其他业务逻辑。
安全性:通过预签名的策略和签名值,可以确保只有授权的用户才能上传文件,并且文件只能上传到指定的位置。
然而,这种技术也需要注意一些安全问题,如保护访问密钥、防止策略被篡改等。因此,在实施时应该仔细考虑并遵循最佳实践。
IAM 的权限配置
没有文档可以参考具体
权限是如何配置的,但是我自己实践了一下基本的权限配置,你可以复制粘贴下面的这个策略配置 JSON 来作为 Presigned Post Policy 的其中一部分授权给相关的 IAM 用户:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PresignedPostPolicy",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::yourbucketname/temp/*"
}
]
}
注意这里 Resource
背后的 arn:aws:s3:::yourbucketname/temp/*
代表了授权该 Policy 的 IAM 用户可以签署 Post Policy 并在之后允许直接对 Bucket 接入点进行 POST 操作下面的资源:
yourbucketname
的存储桶- 存储桶下方目录为
temp/
开头的任意文件
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PresignedPostPolicy",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:PutObjectAcl"
],
"Resource": "arn:aws:s3:::yourbucketname/temp/*" // [!code hl]
}
]
}
当然,这里只是对 IAM 用户做一层限制,实际的 temp/*
目录下的权限可以根据具体的业务需求再去通过 Policy 去限制一次。
Node.js 服务端
其实很简单,首先在本地 Node.js 服务端项目中安装 @aws-sdk/s3-presigned-post
pnpm i @aws-sdk/s3-presigned-post
如果你用 @antfu/ni
的话也可以用下面的命令来安装
ni @aws-sdk/s3-presigned-post
安装之后用下面的代码就可以导入用于创建上传的时候使用的预签署 Policy 的函数 createPresignedPost
了:
import {
createPresignedPost } from '@aws-sdk/s3-presigned-post';
用法的话,我一般会这么封装:
import {
createPresignedPost } from '@aws-sdk/s3-presigned-post';
export enum UploadingPolicyContentType {
Image = 'image/',
}
export async getSignedUploadPolicy(
dir: string,
contentType: UploadingPolicyContentType,
): Promise<{
url: