You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

.NetCore+Angular通过预签名URL上传S3时签名不匹配问题排查

S3预签名URL上传图片签名不匹配问题排查与疑问解答

我想用.NetCore后端生成带密钥的S3预签名URL,再通过Angular前端用这个URL上传图片。现在前后端代码都写了,但请求返回错误:

The request signature we calculated does not match the signature you provided. Check your key and signing method.

同时有两个疑问:

  • 能否用GetPreSignedURL实现文件上传?
  • 该方法是否负责签名及所有安全相关事宜?

签名不匹配的原因及修复

你的前端上传代码是问题核心:用PUT请求预签名URL时,不能把文件包装成FormData传递。预签名URL是基于请求的完整参数(包括内容格式、请求头)生成的,FormData会自动添加额外的边界标识和请求头,导致实际请求的签名和预签名URL的签名完全不匹配。

修复后的Angular代码应该直接传递文件二进制内容,并设置正确的MIME类型:

uploadFile(file: any, preSignedUrl: GetMediaPostRequestSuccess): Observable<HttpEvent<any>> {
  // 直接传文件对象,不要用FormData
  return this._http.put(preSignedUrl.bucketUri, file, {
    headers: { 
      'Content-Type': file.type, // 必须和文件实际类型一致,否则签名校验失败
      'dont-modify-this-one': '' // 继续保留避免拦截器添加Authorization头
    },
    observe: 'events'
  })
}

另外还要核对后端的几个关键点:

  • 确认RegionEndpoint和Liara存储的实际区域一致,不要硬编码USEast1,区域不匹配会直接导致签名错误。
  • 检查GenerateResourceKey生成的Key,预签名时的Key必须和最终存储到S3的Key完全一致。
  • 确认LIARA_ACCESS_KEY和LIARA_SECRET_KEY没有拼写错误、多余空格或权限不足。

疑问解答

  1. 能否用GetPreSignedURL实现文件上传?
    完全可以。只要在GetPreSignedUrlRequest里把Verb设置为HttpVerb.PUT(单文件上传常用方式)或者POST,生成的预签名URL就支持对应的上传操作。PUT方式逻辑简单,适合直接上传单个文件。

  2. 该方法是否负责签名及所有安全相关事宜?
    是的。GetPreSignedURL会根据你的密钥、请求参数(Bucket名、Key、HTTP方法、过期时间等)生成包含签名的完整URL。这个URL本身已经包含了所有认证信息,前端使用时不需要再携带Authorization头(你的代码里拦截器的处理是对的)。只要URL在过期时间内,且请求的内容、参数和预签名时的预期一致,就能完成上传,无需后端再做额外安全验证。


后端.NetCore代码

public ServiceResponse GetPreSigned(FileCategory prepend, string append = null)
{
    var mediaId = Guid.NewGuid();
    var config = new AmazonS3Config
    {
        SignatureVersion = "v4",
        RegionEndpoint = RegionEndpoint.USEast1, // 注意:需和Liara实际区域匹配
        ServiceURL = _config.LIARA_ENDPOINT
    };

    var amazonS3Client = new AmazonS3Client(_config.LIARA_ACCESS_KEY, _config.LIARA_SECRET_KEY, config);

    Amazon.S3.Model.GetPreSignedUrlRequest ccc = new Amazon.S3.Model.GetPreSignedUrlRequest()
    {
        BucketName = _config.LIARA_BUCKET_NAME,
        Key = GenerateResourceKey(mediaId, prepend.ToString(), append),
        Expires = DateTime.Now.AddMinutes(30),
        Verb = HttpVerb.PUT,
    };
    
    return new GetMediaPostRequestSuccess
    {
        MediaKey = GenerateResourceKey(mediaId, prepend.ToString(), append),
        BucketUri = amazonS3Client.GetPreSignedURL(ccc)
    };
}

内容的提问来源于stack exchange,提问作者amir

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.19 23:25:35