AWS S3临时上传和下载权限的获取
背景
S3用于文件存储,类似于阿里云的OSS,使用的这类云存储面临一个问题是用户权限的问题,如普通用户没用上传的权限,不能上传自身相关的文件,或者对于一个隐私文件,用户想访问怎么办。
AWS可以通过Lambda可以比较精细控制S3访问权限,但是在这不作讨论
我们讨论的是通过自己的服务器控制S3访问权限,对于私有文件的访问或者需要获取上传的权限,比较简单的方式是直接把Key下发给客户端,客户端通过Key去访问或上传,但是面临一个问题就是安全性,如果Key泄露,则会导致信息的问题。
因此必须有一种获取临时的上传或者获取的权限的接口,AWS SDK提供这种方式。下面我们以Python为基础说明相关问题
获取临时的上传权限
AWS提供python boto3包作为官方的SDK,通过generate_presigned_post函数提供临时的上传权限。
import boto3
client = boto3.client(
's3', aws_access_key_id='Test_key_id',
aws_secret_access_key='Test_key'
)
# 设置访问权限
fields = {"acl": "public-read"}
# 设置访问权限和文件大小 1K- 500K
conditions = [
{"acl": "public-read"},
["content-length-range", 1024, 500 * 1024]
]
file_name = "test_image_file.jpg"
# 300秒内有效
post = client.generate_presigned_post(
Bucket='jibon', Key=file_name, Fields=fields,
Conditions=conditions, ExpiresIn=300
)
# 返回post是一个字典
{
'url': 'https://mybucket.s3.amazonaws.com',
'fields': {
'acl': 'public-read',
'key': 'mykey', 'signature': 'mysignature', 'policy': 'mybase64 encoded policy'
}
}
# 300秒内有效,文件上传
import requests
file_upload = open('test.jpg', 'r')
file = {"file": file_upload.read()}
res = requests.post(post['url'], data=post['fields'], files=file)
print(res)
获取文件临时访问权限
通过generate_presigned_url函数提供隐私文件临时的下载权限。
import logging
import boto3
from botocore.exceptions import ClientError
def create_presigned_url(bucket_name, object_name, expiration=3600):
"""Generate a presigned URL to share an S3 object
:param bucket_name: string
:param object_name: string
:param expiration: Time in seconds for the presigned URL to remain valid
:return: Presigned URL as string. If error, returns None.
"""
# Generate a presigned URL for the S3 object
s3_client = boto3.client(
's3', aws_access_key_id='test_key_id',
aws_secret_access_key='test_key'
)
try:
response = s3_client.generate_presigned_url(
'get_object',
Params={'Bucket': bucket_name,
'Key': object_name},
ExpiresIn=expiration
)
except ClientError as e:
logging.error(e)
return None
# The response contains the presigned URL
return response
if __name__ == '__main__':
response = create_presigned_url("test_bucket", "test_file.jpg")
# response 则为访问地址
print(response)