You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

AWS Java SDK签名不匹配问题:凭证正确仍报错?实为复制粘贴失误

解决S3签名不匹配问题:排查与修正方案

问题更新说明

先跟大家同步下最终排查结果:这个问题其实是我复制粘贴AWS密钥时犯的低级错误(比如多了空格或者漏了字符)。同时整理几个关键要点,帮遇到类似问题的朋友避坑:

原问题回顾

我在开发Spark程序向S3写入JSON时,碰到了这个经典的签名错误:

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

为了定位问题,我用AWS Java SDK的示例程序做了测试:

  • 当凭证正常放在~/.aws/credentials里时,程序完全没问题;
  • 但把这个文件移走,改用代码内联硬编码凭证后,无论怎么试都失败,核心代码片段如下:
// 核心内联凭证代码
AWSCredentialsProvider provider = new AWSCredentialsProvider() {
    @Override
    public AWSCredentials getCredentials() {
        return new AWSCredentials () {
            @Override
            public String getAWSAccessKeyId() {
                return "somethingsomething"; // 复制自~/.aws/credentials
            }
            @Override
            public String getAWSSecretKey() {
                return "somethingsomethingelse"; // 复制自~/.aws/credentials
            }
        };
    }
    @Override
    public void refresh() { }
};

AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_EAST_1)
    .withCredentials(provider)
    //.withClientConfiguration(clientConfiguration)
    .build();

问题排查与解决办法

除了我碰到的复制粘贴错误,还有几个常见原因和对应解决方案:

  • 签名版本不兼容:AWS S3现在默认使用V4签名,但有些旧区域或者特殊配置需要V2签名。你代码里已经写了clientConfiguration.setSignerOverride("S3SignerType");(这是指定V2签名的配置),只是被注释掉了,取消注释这行大概率能解决签名方法不匹配的问题。
  • 凭证格式错误:一定要确保内联的密钥和~/.aws/credentials里的完全一致,别带多余的换行、空格或者引号——这些肉眼难查的小问题经常导致签名失败。
  • 区域不匹配:确认withRegion(Regions.US_EAST_1)和你的S3桶实际所在区域完全一致,区域不对也会触发签名验证失败。

另外,内联凭证的代码可以更简洁,没必要自定义AWSCredentialsProvider,用BasicAWSCredentialsAWSStaticCredentialsProvider就够了,代码更易读也更少出错:

// 简化后的凭证配置
AWSCredentials credentials = new BasicAWSCredentials("your-access-key", "your-secret-key");
AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
    .withRegion(Regions.US_EAST_1)
    .withCredentials(new AWSStaticCredentialsProvider(credentials))
    .withClientConfiguration(clientConfiguration)
    .build();

完整修正后的程序

import com.amazonaws.AmazonServiceException;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.SdkClientException;
import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.ObjectMetadata;
import com.amazonaws.services.s3.model.PutObjectRequest;
import java.io.File;
import java.io.IOException;

public class UploadObject {
    public static void main(String[] args) throws IOException {
        String bucketName = "cbedford-sqlshackdemocli-test-only";
        String stringObjKeyName = "durango.saturday1";
        String fileObjKeyName = "clean.money.txt";
        String fileName = "/tmp/x";

        ClientConfiguration clientConfiguration = new ClientConfiguration();
        // 启用V2签名,适配部分场景下的签名要求
        clientConfiguration.setSignerOverride("S3SignerType");

        // 使用官方推荐的简洁凭证方式
        AWSCredentials credentials = new BasicAWSCredentials(
            "somethingsomething", 
            "somethingsomethingelse"
        );

        try {
            AmazonS3 s3Client = AmazonS3ClientBuilder.standard()
                .withRegion(Regions.US_EAST_1)
                .withCredentials(new AWSStaticCredentialsProvider(credentials))
                .withClientConfiguration(clientConfiguration)
                .build();

            // 上传字符串对象
            s3Client.putObject(bucketName, stringObjKeyName, "Uploaded String Object");

            // 上传文件并设置元数据
            PutObjectRequest request = new PutObjectRequest(bucketName, fileObjKeyName, new File(fileName));
            ObjectMetadata metadata = new ObjectMetadata();
            metadata.setContentType("plain/text");
            metadata.addUserMetadata("title", "someTitle");
            request.setMetadata(metadata);
            s3Client.putObject(request);
        } catch (AmazonServiceException e) {
            e.printStackTrace();
        } catch (SdkClientException e) {
            e.printStackTrace();
        }
    }
}

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

火山引擎 最新活动