DaLei@home:~$

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)