首页 > 解决方案 > AWS S3 使用查询参数对请求进行身份验证以下载具有自定义名称的文件

问题描述

我正在尝试创建一个可以让用户从 S3 存储桶下载文件的文件的签名 URL。我正在遵循用docs编写的这种方式。生成的签名运行良好,并且在用户访问 URL 时也可以下载文件。问题是我希望下载文件的名称是自定义的。例如:文件密钥:tg6AbybBgFMidmKy5dz4vVXZ文件名:test.xlsx

该文件使用密钥保存在 S3 上,没有文件扩展名。

因此,当用户下载文件时,它是无扩展名的,因此操作系统无法识别。我希望它与FileName. 我尝试添加response-content-disposition查询,但它引发了错误:

在此处输入图像描述

下面是我现在正在使用的代码。

    # Create a date for headers and the credential string
    time = datetime.datetime.utcnow()
    amz_date = time.strftime('%Y%m%dT%H%M%SZ')
    datestamp = time.strftime('%Y%m%d') # Date w/o time, used in credential scope

    # **CREATE A CANONICAL REQUEST**
    canonical_uri = '/' + document_key
    canonical_headers = 'host:' + bucket_url + '\n'

    algorithm = 'AWS4-HMAC-SHA256'
    credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'

    # Create the canonical query string in URL-encoded (space=%20).
    canonical_querystring = 'response-content-disposition=attachment; filename="' + document_name + '"; filename*=UTF-8\'\'' + document_name
    canonical_querystring += '&response-content-type=' + document_type
    canonical_querystring += '&X-Amz-Algorithm=AWS4-HMAC-SHA256'
    canonical_querystring += '&X-Amz-Credential=' + quote_plus(access_key + '/' + credential_scope, safe='')
    canonical_querystring += '&X-Amz-Date=' + amz_date
    canonical_querystring += '&X-Amz-Expires=' + url_expiry
    canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers

    canonical_request = request_method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers.lower() + '\n' + signed_headers.lower()

    # CREATE THE STRING TO SIGN
    string_to_sign = algorithm + '\n' +  amz_date + '\n' +  credential_scope + '\n' +  hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()
    
    # CALCULATE THE SIGNATURE
    signing_key = getSignatureKey(secret_key, datestamp, region, service)
    signature = hmac.new(signing_key, (string_to_sign).encode("utf-8"), hashlib.sha256).hexdigest()

    # ADD SIGNING INFORMATION TO THE REQUEST
    canonical_querystring += '&X-Amz-Signature=' + signature
    
    # Merge for downloadable URL
    download_url = 'https://' + bucket_url + canonical_uri +'?' + canonical_querystring

我没有使用 AWS 开发工具包。我正在尝试自己做!

编辑:即使添加&了丢失的内容,我也得到了签名不匹配。

标签: python-3.xamazon-web-servicesamazon-s3

解决方案


问题在于编码,我错过&canonical_querystring = 'X-Amz-Algorithm!它杀死了我环顾所有论坛并尝试不同事物的 3 天!这是工作代码!


  # Create a date for headers and the credential string
    time = datetime.datetime.utcnow()
    amz_date = time.strftime('%Y%m%dT%H%M%SZ')
    datestamp = time.strftime('%Y%m%d') # Date w/o time, used in credential scope

    # **CREATE A CANONICAL REQUEST**
    canonical_uri = '/' + document_key
    canonical_headers = 'host:' + bucket_url + '\n'

    algorithm = 'AWS4-HMAC-SHA256'
    credential_scope = datestamp + '/' + region + '/' + service + '/' + 'aws4_request'

    # Create the canonical query string in URL-encoded (space=%20).
    canonical_querystring = 'X-Amz-Algorithm=AWS4-HMAC-SHA256'
    canonical_querystring += '&X-Amz-Credential=' + quote_plus(access_key + '/' + credential_scope, safe='')
    canonical_querystring += '&X-Amz-Date=' + amz_date
    canonical_querystring += '&X-Amz-Expires=' + url_expiry
    canonical_querystring += '&X-Amz-SignedHeaders=' + signed_headers
    canonical_querystring += '&response-content-disposition=' + quote('attachment; filename=\"' + document_name + '\"; filename*=UTF-8\'\'' + document_name, safe='')
    canonical_querystring += '&response-content-type=' + quote(document_type, safe='')

    canonical_request = request_method + '\n' + canonical_uri + '\n' + canonical_querystring + '\n' + canonical_headers.lower() + '\n' + signed_headers.lower() + '\n' + 'UNSIGNED-PAYLOAD'

    # CREATE THE STRING TO SIGN
    string_to_sign = algorithm + '\n' +  amz_date + '\n' +  credential_scope + '\n' +  hashlib.sha256(canonical_request.encode('utf-8')).hexdigest()

    # CALCULATE THE SIGNATURE
    signing_key = getSignatureKey(secret_key, datestamp, region, service)
    signature = hmac.new(signing_key, (string_to_sign).encode("utf-8"), hashlib.sha256).hexdigest()

    # ADD SIGNING INFORMATION TO THE REQUEST
    canonical_querystring += '&X-Amz-Signature=' + signature
    
    # Merge for downloadable URL
    download_url = 'https://' + bucket_url + canonical_uri +'?' + canonical_querystring

我正在使用

quote_plus('attachment; filename=\"' + document_name + '\"; filename*=UTF-8\'\'' + document_name,)

而不是我不得不使用

quote('attachment; filename=\"' + document_name + '\"; filename*=UTF-8\'\'' + document_name, safe='')

使用此方法/逻辑,您可以生成具有自定义文件名的 S3 对象链接,而无需使用 aws-sdk


推荐阅读