背景信息少,
我建立了一个互动网站,用户可以将图像上传到S3。我构建了它,因此使用签名请求(python django后端)将图像上传从浏览器直接传送到AWS S3。
现在的问题是,用户希望能够旋转图像。我同样我希望这样设置,以便用户的请求直接来自浏览器。我构建了一个AWS Lambda函数并将其附加到web api,它将接受POST请求。我一直在测试,我终于开始工作了。该函数需要2个输入key
和rotate_direction
,它们作为POST变量传递给web api。它们进入event
变量的python函数。这是简单的Lambda函数:
from __future__ import print_function
import boto3
import os
import sys
import uuid
from PIL import Image
s3_client = boto3.client('s3')
def rotate_image(image_path, upload_path, rotate_direction):
with Image.open(image_path) as image:
if rotate_direction == "right":
image.rotate(-90).save(upload_path)
else:
image.rotate(90).save(upload_path)
def handler(event, context):
bucket = 'the-s3-bucket-name'
key = event['key']
rotate_direction = event['rotate_direction']
download_path = '/tmp/{}{}'.format(uuid.uuid4(), key)
upload_path = '/tmp/rotated_small-{}'.format(key)
s3_client.download_file(bucket, key, download_path)
rotate_image(download_path, upload_path, rotate_direction)
s3_client.delete_object(Bucket=bucket, Key=key)
s3_client.upload_file(upload_path, bucket, key)
return { 'message':'rotated' }
一切正常。那么现在我的问题是如何为这个系统强制执行某种身份验证?每个映像的所有权详细信息都驻留在django Web服务器上。虽然所有图像都被视为“公开”,但我希望强制只允许每个图像的所有者旋转自己的图像。
通过这个项目,我一直在通过浏览器发出内容请求进入新的领域。我可以理解如何通过仅从Web服务器发出POST请求来控制访问,在那里我可以验证图像的所有权。是否仍然可以从浏览器发出请求?
答案 0 :(得分:5)
TL; DR解决方案:创建一个Cognito Identity Pool,分配策略用户只能上传以其身份ID为前缀的文件。
如果我正确理解您的问题,您希望为存储在S3上的图片设置一种方式公开,但只有可由上传的用户编辑。实际上,您可以在浏览器中验证文件所有权,旋转图像并将旋转后的图像上传到S3,而无需通过Lambda函数。
步骤1:创建Cognito用户池以创建用户目录。如果您已拥有用户登录/注册身份验证系统,则可以跳过此步骤。
步骤2:创建Cognito Identify Pool以启用联合身份,以便您的用户可以从身份池获取临时AWS凭证,并使用它将文件上传到S3而无需通过您的服务器/ lambda。
步骤3:创建Cognito Identity Pool时,您可以定义允许用户访问哪些S3资源的策略。这是一个示例政策
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": [
"*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::YOUR_S3_UPLOADS_BUCKET_NAME/*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::YOUR_S3_UPLOADS_BUCKET_NAME/${cognito-identity.amazonaws.com:sub}*"
]
}
]
}
注意第二个块将“S3:GetObject”分配给S3存储桶中的所有文件;第三个块将“S3:PutObject”分配给前缀为用户的Cognito身份ID的文件。
步骤4:在前端JS中,从Cognito Identity Pool获取临时凭证
export function getAwsCredentials(userToken) {
const authenticator = `cognito-idp.${config.cognito.REGION}.amazonaws.com/${config.cognito.USER_POOL_ID}`;
AWS.config.update({ region: config.cognito.REGION });
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: config.cognito.IDENTITY_POOL_ID,
Logins: {
[authenticator]: userToken
}
});
return new Promise((resolve, reject) => (
AWS.config.credentials.get((err) => {
if (err) {
reject(err);
return;
}
resolve();
})
));
}
步骤5:使用凭证将文件上传到S3,使用用户的Cognito身份ID为文件名添加前缀。
export async function s3Upload(file, userToken) {
await getAwsCredentials(userToken);
const s3 = new AWS.S3({
params: {
Bucket: config.s3.BUCKET,
}
});
const filename = `${AWS.config.credentials.identityId}-${Date.now()}-${file.name}`;
return new Promise((resolve, reject) => (
s3.putObject({
Key: filename,
Body: file,
ContentType: file.type,
ACL: 'public-read',
},
(error, result) => {
if (error) {
reject(error);
return;
}
resolve(`${config.s3.DOMAIN}/${config.s3.BUCKET}/${filename}`);
})
));
}