【问题标题】:Amazon S3 - How to properly build URLs pointing to the objects in a bucket?Amazon S3 - 如何正确构建指向存储桶中对象的 URL?
【发布时间】:2011-08-22 09:36:57
【问题描述】:

我正在使用 Amazon S3 环境来存储 C# Web 应用程序的图像。从S3 documentation 我了解到,访问对象的基本 URL 看起来像

http://[bucket-name].S3.amazonaws.com/[key]

我知道可以为存储桶中的对象构建过期 URL。两个问题:

  1. 一般应该使用过期网址吗?
  2. 我将如何构建一个即将过期的 url?

【问题讨论】:

  • 感谢您提出有关基本 URL 的问题和信息!对我来说,这是一个问题比任何答案都更有用的情况:)

标签: c# url amazon-s3


【解决方案1】:

如果你想限制访问,你只需要构建过期的 url。

这里有一些代码可以生成 3 分钟后过期的签名 url。

using (var s3Client = AWSClientFactory.CreateAmazonS3Client("MyAccessKey", "MySecretKey"))
{
    GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
        .WithBucketName("MyBucketName")
        .WithKey("MyFileKey")
        .WithProtocol(Protocol.HTTP)
        .WithExpires(DateTime.Now.AddMinutes(3));

    string url = s3Client.GetPreSignedURL(request);
}

【讨论】:

  • @Lee Gunn 我需要一个没有过期时间的 URL,有没有办法做到这一点?
  • @ArturKeyan - 尝试不使用它,如果它不起作用我想你可以使用一个大的到期日期。
【解决方案2】:

这是来自 S3SignURL 的代码,它不使用外部 DLL 的纯核心 C#

https://github.com/DigitalBodyGuard/S3SignURL/

using System;
using System.Collections.Generic;
using System.Text;

namespace s3_polocySigning
{
    public static class Encode
    {
     //   static string thanks = "http://stackoverflow.com/questions/6999648/signing-post-form-in-c-sharp-for-uploading-to-amazon-s3";
        public static string BuildURL(string AccessKey, string SecretKey, DateTime timeToExpire, string BucketName, string FileKey)
        {
            System.Security.Cryptography.HMAC hmacProvider = System.Security.Cryptography.HMAC.Create();
            string returnString = string.Empty;
            hmacProvider.Key = System.Text.ASCIIEncoding.ASCII.GetBytes(SecretKey);
            string expirationString = ConvertToUnixTimestamp(timeToExpire).ToString();
            //System.Uri.UriSchemeHttp &/ System.Web.HttpUtility.UrlEncode
            string assembledRequest = "GET" + "\n" + "\n" + "\n" + expirationString + "\n" + "/" + BucketName + "/" + UrlEncode(FileKey);
            byte[] hashedSignature = hmacProvider.ComputeHash(System.Text.ASCIIEncoding.ASCII.GetBytes(assembledRequest));

            returnString = Convert.ToBase64String(hashedSignature);
            return "https://" + "s3.amazonaws.com/" + BucketName + "/" + FileKey + "?AWSAccessKeyId=" + AccessKey + "&Expires=" + expirationString + "&Signature=" + UrlEncode(returnString);
        }
        private static double ConvertToUnixTimestamp(DateTime ExpDate)
        {
            if (DateTime.MinValue == ExpDate)
                return  2133721337;
            DateTime origin = new DateTime(1970, 1, 1, 0, 0, 0, 0);
            TimeSpan diff = ExpDate - origin;
            return Convert.ToDouble(Math.Floor(diff.TotalSeconds));
        }






        public static string GetSig(string policyStr, string secretKey)
        {
            policyStr = GetBase64_string(policyStr);
            var signature = new System.Security.Cryptography.HMACSHA1(GetBase64(secretKey));
            var bytes = GetBase64(policyStr);
            var moreBytes = signature.ComputeHash(bytes);
            var encodedCanonical = Convert.ToBase64String(moreBytes);
            return encodedCanonical;
        }
        public static string GetBase64_string(string policyStr)
        {
            policyStr = policyStr.Replace("/r", "").Replace("/n", "").Replace(System.Environment.NewLine, "\n");
            return Convert.ToBase64String(Encoding.ASCII.GetBytes(policyStr));
        }
        public static byte[] GetBase64(string policyStr)
        {
            return Encoding.ASCII.GetBytes(policyStr);
        }




       // ThanksTo = "http://www.west-wind.com/weblog/posts/2009/Feb/05/Html-and-Uri-String-Encoding-without-SystemWeb";
        // avoid useing System.Web.HttpUtility.UrlEncode

        /// <summary>
        /// UrlEncodes a string without the requirement for System.Web
        /// </summary>
        /// <param name="String"></param>
        /// <returns></returns>
        // [Obsolete("Use System.Uri.EscapeDataString instead")]
        public static string UrlEncode(string text)
        {
            // Sytem.Uri provides reliable parsing
            return System.Uri.EscapeDataString(text);
        }

        /// <summary>
        /// UrlDecodes a string without requiring System.Web
        /// </summary>
        /// <param name="text">String to decode.</param>
        /// <returns>decoded string</returns>
        public static string UrlDecode(string text)
        {
            // pre-process for + sign space formatting since System.Uri doesn't handle it
            // plus literals are encoded as %2b normally so this should be safe
            text = text.Replace("+", " ");
            return System.Uri.UnescapeDataString(text);
        }

        /// <summary>
        /// Retrieves a value by key from a UrlEncoded string.
        /// </summary>
        /// <param name="urlEncoded">UrlEncoded String</param>
        /// <param name="key">Key to retrieve value for</param>
        /// <returns>returns the value or "" if the key is not found or the value is blank</returns>
        public static string GetUrlEncodedKey(string urlEncoded, string key)
        {
            urlEncoded = "&" + urlEncoded + "&";

            int Index = urlEncoded.IndexOf("&" + key + "=", StringComparison.OrdinalIgnoreCase);
            if (Index < 0)
                return "";

            int lnStart = Index + 2 + key.Length;

            int Index2 = urlEncoded.IndexOf("&", lnStart);
            if (Index2 < 0)
                return "";

            return UrlDecode(urlEncoded.Substring(lnStart, Index2 - lnStart));
        }
    }
}

【讨论】:

  • 很有希望,但这不适用于dotnet core,如果将System.Security.Cryptography.HMAC hmacProvider = System.Security.Cryptography.HMAC.Create();更改为var hmacProvider = new HMACSHA1(Encoding.ASCII.GetBytes(SecretKey))则无所谓。 AWS S3 http 服务器总是返回签名失败。
【解决方案3】:

使用第 3 版 S3 SDK,Amazon 已将 api 更改为与 Lee Gunn 的答案不兼容。文档在这里:

http://docs.aws.amazon.com/AmazonS3/latest/dev/ShareObjectPreSignedURLDotNetSDK.html

using (var s3Client = new AmazonS3Client(Amazon.RegionEndpoint.USEast1))
{
    GetPreSignedUrlRequest request1 = new GetPreSignedUrlRequest
    {
        BucketName = "MyBucket",
        Key = "MyKey",
        Expires = DateTime.Now.AddMinutes(5)
    };
    string urlString = s3Client.GetPreSignedURL(request1);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-07-07
    • 2014-12-23
    • 1970-01-01
    • 2013-08-23
    • 2012-04-12
    • 2012-05-26
    • 2015-11-22
    • 2018-10-22
    相关资源
    最近更新 更多