如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?

Posted

技术标签:

【中文标题】如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?【英文标题】:How to generate pre-signed Amazon S3 url for a vanity domain, using amazon sdk? 【发布时间】:2012-03-24 10:32:08 【问题描述】:

我有一个名为 foo.example.com 的 s3 存储桶,它的 CNAME 都是正确的。

我正在切换到最新的 AWS .net SDK。

我希望生成预签名的网址,例如:

http://foo.example.com/myfile.txt?s3_params_here

注意那里的虚荣名称。

我有:

string bucketName = "foo.example.com";

AmazonS3Client s3Client = new AmazonS3Client("bar", "xxx",
    new AmazonS3Config
    
        ServiceURL = bucketName, 
        CommunicationProtocol = Protocol.HTTP
    );


string key = "myfile.txt";


GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
.WithBucketName(bucketName)
.WithKey(key)
.WithExpires(DateTime.Now.AddMinutes(5))
.WithProtocol(Protocol.HTTP);

string url = s3Client.GetPreSignedURL(request);

我得到的网址是这样的:

http://foo.example.com.foo.example.com/myfile.txt?AWSAccessKeyId=bar&Expires=1331069777&Signature=234KoUUvfE1nCcs2vLj9RQUhqF8%3D

这显然是错误的。

我已经尝试了 ServiceURL、bucketname 等多种不同的变体,但似乎没有任何效果。

我找不到任何好的文档 - 这样做的正确方法是什么?

谢谢。

【问题讨论】:

我刚刚再次删除了我的答案(永久有效),并且在我能够在 .NET 中真正重现端到端解决方案之前,我不会再添加一个答案。众所周知,自定义域的预签名 URL 原则上可以工作(例如,参见这个古老的 AWS 团队对 CNAME alias with pre-signed query 的回复,我也相应地使用了它们;Ruby 示例中的 VANITY 参数已被弃用,并且在 AWS 中不可用无论如何,适用于 .NET 的 SDK,它应该像这样工作,AFAIK - 再次抱歉给您带来麻烦! 【参考方案1】:

更新[解决方法]

同时,我已经解决了我的自相矛盾的测试结果,这些结果分别源于非系统测试和 URL 操作。以下解决方法对我有用(即经过测试且可重现),只需从您的解决方案开始:

string bucketName = "foo.example.com";

// [...]

GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
    .WithBucketName(bucketName)
    .WithKey(key)
    .WithExpires(DateTime.Now.AddMinutes(32))
    .WithProtocol(Protocol.HTTP);

现在这会产生带有重复域名的错误 URL,即http://foo.example.com.foo.example.com/myfile.txt?[...]

但可以简单地删除重复项,例如:

string url = s3Client.GetPreSignedURL(request);

// KLUDGE: remove duplicate domain name.
url = url.Replace(bucketName + "." + bucketName, bucketName);

通过解决下面概述的所需方法遇到的限制,这为我生成了一个正确的工作预签名 URL(即http://foo.example.com/myfile.txt?[...])。

理由

像这样操作生成的 URL 似乎很奇怪,但这对查询字符串身份验证没有影响符合这些签名的创建方式,请参阅 Query String Request Authentication Alternative,您将在其中找到 伪语法说明查询字符串请求身份验证方法

StringToSign = HTTP-VERB + "\n" +
    Content-MD5 + "\n" +
    Content-Type + "\n" +
    Expires + "\n" +
    CanonicalizedAmzHeaders +
    CanonicalizedResource;    

也就是说,域名根本不用于签名创建,而只是关于资源本身的信息;引用的伪语法片段正下方的示例查询字符串请求身份验证部分用实际资源说明了这一点。

评估

我不知道我们是否仍然存在误解,或者这是否可能只是 AWS SDK for .NET 中的一个错误,请参见例如Why is my S3 pre-signed request invalid when I set a response header override that contains a “+”? 用于通过类似解决方法解决的相关错误,但同时已修复;因此,这可能会升级到 AWS 论坛和/或支持渠道,以获得适当的答案或解决方案。

祝你好运!


期望的答案 [功能失调]

S3 CNAME 处理已经暗示了存储桶名称,因此您只需从 GetPreSignedUrlRequest 中删除存储桶名称,即它应该如下所示:

GetPreSignedUrlRequest request = new GetPreSignedUrlRequest()
    .WithKey(key)
    .WithExpires(DateTime.Now.AddMinutes(5))
    .WithProtocol(Protocol.HTTP);

我已经用我的一桶测试了它,它按预期工作。

【讨论】:

嗨史蒂芬。谢谢你,但我看不到上面指定了自定义域的位置,以便 S3 CNAME 可以暗示它?我们在这里设置的只是一把钥匙。谢谢。 @Nik:你当然是绝对正确的,我把本地测试收集的信息用我最初的错误答案搞砸了(我在意识到它没有解决问题后偶然删除了它;) - 麻烦您了! ServiceURL 确实必须是您的 CNAME,并且删除已经隐含的存储桶名称可以解决重复问题。 当我删除 WithBucketName() 时,我发现域是正确的,但由于某种原因未在 url 中使用密钥。例如:foo.example.com?AWSAccessKeyId=bar&Expires=1331078589&S…。你能确认这绝对适合你吗? @Nik:我又试了一次,至少能够想出一个解决方法,这次测试和端到端地复制了;) 感谢您的坚持,Steffen - 它有效!对我来说,这似乎是 AWS 开发工具包中的一个错误。【参考方案2】:

presignedURL 在对请求进行签名后返回一个 URL 对象。我用过同样的,>没有真正的问题,但有一些事情需要考虑:

    确保您考虑的对象 URL 没有“//”,如果 >您开始存储路径以“/”开头,则很容易发生这种情况,您会将对象存储在某个路径中 >像 https:///x/y/z/abc.png 这样的资源的关键是 x/y/z/abc.png >而不是 /x/y/z/abc.png

    1234563您的原始 awsURL 应该可以解决>任何编码问题。

希望这会有所帮助..

本质上,您需要对返回的 url 对象使用 url.getQuery,而不是简单地将其附加到存储桶的末尾。

https://forums.aws.amazon.com/thread.jspa?threadID=70521

【讨论】:

该链接与编码问题有关。您能否更清楚地了解它如何解决我的问题?谢谢!

以上是关于如何使用 amazon sdk 为虚域生成预签名的 Amazon S3 url?的主要内容,如果未能解决你的问题,请参考以下文章

使用预签名 URL 将文件上传到 Amazon S3 时出现 CORS 错误

如何使用预签名的 url 将对象放入 amazon s3?

通过使用 AWS-SDK PHP 生成的预签名帖子拒绝 AWS S3 上传访问

通过使用 AWS-SDK PHP 生成的预签名帖子拒绝 AWS S3 上传访问

Amazon S3 预签名 URL - 手动或一次性上传无效

Amazon s3 预签名 URL 受 IP 地址限制