我已经在网上搜索了两天多,并且可能已经浏览了大多数在线记录的场景和解决方法,但到目前为止对我没有任何帮助。
我使用的是在 PHP 5.3 上运行的适用于 PHP V2.8.7 的 AWS 开发工具包。
我正在尝试使用以下代码连接到我的 Amazon S3 存储桶:
// Create a `Aws` object using a configuration file
$aws = Aws::factory('config.php');
// Get the client from the service locator by namespace
$s3Client = $aws->get('s3');
$bucket = "xxx";
$keyname = "xxx";
try {
$result = $s3Client->putObject(array(
'Bucket' => $bucket,
'Key' => $keyname,
'Body' => 'Hello World!'
));
$file_error = false;
} catch (Exception $e) {
$file_error = true;
echo $e->getMessage();
die();
}
我的 config.php 文件如下:
return [
// Bootstrap the configuration file with AWS specific features
'includes' => ['_aws'],
'services' => [
// All AWS clients extend from 'default_settings'. Here we are
// overriding 'default_settings' with our default credentials and
// providing a default region setting.
'default_settings' => [
'params' => [
'credentials' => [
'key' => 'key',
'secret' => 'secret'
]
]
]
]
];
它产生以下错误:
我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
我已经检查了我的访问密钥和秘密至少 20 次,生成了新的,使用不同的方法来传递信息(即配置文件并在代码中包含凭据),但目前没有任何工作。
secret
),并使用它来根据您的访问密钥、当前时间戳以及许多其他因素来计算签名。请参阅docs.aws.amazon.com/general/latest/gr/…。这是一个远景,但考虑到它们包括时间戳,也许您本地环境的时间已经关闭?
Content-Length
) 时发生。 (长版:我们直接将输入流从 Java HttpServletRequest
传递到 S3 客户端,并通过元数据将 request.getContentLength()
作为 Content-Length
传递;当 servlet(随机)接收分块请求时(Transfer-Encoding: chunked
) , getContentLength()
返回 -1
- 这导致 putObject
失败(随机)。晦涩难懂;但显然是我们的错,因为我们传递了不正确的对象大小。)
调试了两天,终于发现问题了……
我分配给对象的键以句点开头,即..\images\ABC.jpg
,这导致了错误的发生。
我希望 API 提供更有意义和相关的错误消息,唉,我希望这对其他人有帮助!
我使用错误的凭据收到此错误。我认为最初粘贴时有看不见的字符。
key_hash_lala/key_hash_continues
,它只选择了一个部分。唉,告诉用户“密码错误,伙计!”有多难?
尝试复制带有一些 UTF8 字符的对象时,我遇到了同样的问题。下面是一个 JS 示例:
var s3 = new AWS.S3();
s3.copyObject({
Bucket: 'somebucket',
CopySource: 'path/to/Weird_file_name_ðÓpíu.jpg',
Key: 'destination/key.jpg',
ACL: 'authenticated-read'
}, cb);
通过使用 encodeURIComponent()
对 CopySource 进行编码来解决
我在nodejs中遇到了同样的错误。但是在 s3 构造函数中添加 signatureVersion
帮助了我:
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
signatureVersion: 'v4',
});
如果您的密钥之前或之后有空格,则似乎主要发生此错误
我的 AccessKey 中有一些特殊字符没有正确转义。
当我复制/粘贴键时,我没有检查特殊字符。让我绊倒了几分钟。
一个简单的反斜杠修复了它。示例(显然不是我真正的访问密钥):
secretAccessKey: 'Gk/JCK77STMU6VWGrVYa1rmZiq+Mn98OdpJRNV614tM'
变成
secretAccessKey: 'Gk\/JCK77STMU6VWGrVYa1rmZiq\+Mn98OdpJRNV614tM'
对于 Python 集 - signature_version s3v4
s3 = boto3.client(
's3',
aws_access_key_id='AKIAIO5FODNN7EXAMPLE',
aws_secret_access_key='ABCDEF+c2L7yXeGvUyrPgYsDnWRRC1AYEXAMPLE',
config=Config(signature_version='s3v4')
)
实际上在Java中我遇到了同样的错误。花了4个小时调试它后,我发现问题出在S3对象中的元数据中,因为在s3文件中放置缓存控件时有空间。这个空间在1.6中是允许的。*版本,但在 1.11.* 中是不允许的,因此会引发签名不匹配错误
Content-Length
,也会发生这种情况
在我的情况下,我在需要使用 s3.getSignedUrl('putObject')
时使用了 s3.getSignedUrl('getObject')
(因为我正在使用 PUT 上传我的文件),这就是签名不匹配的原因。
在 aws-php-sdk 的先前版本中,在弃用 S3Client::factory()
方法之前,您可以将文件路径的一部分或 Key
(在 S3Client->putObject()
parameters 中调用它)放在桶参数。我在生产中使用了一个文件管理器,使用 v2 SDK。由于工厂方法仍然有效,因此我在更新到 ~3.70.0
后没有重新访问此模块。今天我花了两个小时的大部分时间来调试为什么我开始收到这个错误,它最终是由于我传递的参数(过去可以工作):
$s3Client = new S3Client([
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2006-03-01'
]);
$result = $s3Client->putObject([
'Bucket' => 'awesomecatpictures/catsinhats',
'Key' => 'whitecats/white_cat_in_hat1.png',
'SourceFile' => '/tmp/asdf1234'
]);
我必须将存储桶/密钥路径的 catsinhats
部分移至 Key
参数,如下所示:
$s3Client = new S3Client([
'profile' => 'default',
'region' => 'us-east-1',
'version' => '2006-03-01'
]);
$result = $s3Client->putObject([
'Bucket' => 'awesomecatpictures',
'Key' => 'catsinhats/whitecats/white_cat_in_hat1.png',
'SourceFile' => '/tmp/asdf1234'
]);
我认为正在发生的是 Bucket
名称现在正在被 URL 编码。在进一步检查了我从 SDK 收到的确切消息后,我发现:
在 https://s3.amazonaws.com/awesomecatpictures%2Fcatsinhats/whitecats/white_cat_in_hat1.png
上执行 PutObject
时出错
AWS HTTP 错误:客户端错误:PUT https://s3.amazonaws.com/awesomecatpictures%2Fcatsinhats/whitecats/white_cat_in_hat1.png
导致 403 Forbidden
这表明我提供给我的 Bucket
参数的 /
已经通过 urlencode()
,现在是 %2F
。
签名的工作方式相当复杂,但问题归结为存储桶和密钥用于生成加密签名。如果它们在调用客户端和 AWS 中不完全匹配,则请求将被拒绝并返回 403。错误消息确实指出了问题:
我们计算的请求签名与您提供的签名不匹配。检查您的密钥和签名方法。
所以,我的 Key
错了,因为我的 Bucket
错了。
我遇到了同样的问题,我遇到的问题是我导入了错误的环境变量,这意味着我的 AWS 密钥是错误的。在阅读所有答案的基础上,我将验证您的所有访问 ID 和密钥是否正确,并且没有其他字符或任何内容。
对我来说,我使用 axios 并且默认它发送标头
content-type: application/x-www-form-urlencoded
所以我改为发送:
content-type: application/octet-stream
并且还必须将此 Content-Type 添加到 AWS 签名中
const params = {
Bucket: bucket,
Key: key,
Expires: expires,
ContentType: 'application/octet-stream'
}
const s3 = new AWS.S3()
s3.getSignedUrl('putObject', params)
content-type
就可以了。
另一个可能的问题是元值包含非 US-ASCII 字符。对我来说,它有助于在将值添加到 putRequest 时对值进行 UrlEncode:
request.Metadata.Add(AmzMetaPrefix + "artist", HttpUtility.UrlEncode(song.Artist));
request.Metadata.Add(AmzMetaPrefix + "title", HttpUtility.UrlEncode(song.Title));
在我的例子中,我将一个 S3 url 解析为它的组件。
例如:
Url: s3://bucket-name/path/to/file
被解析成:
Bucket: bucket-name
Path: /path/to/file
包含前导“/”的路径部分使请求失败。
我遇到过同样的问题。我有默认方法,PUT 设置为定义预签名的 URL,但试图执行 GET。错误是由于方法不匹配造成的。
当我明知地给出了具有“秘密”价值的错误密钥时,它给出了这个错误。我期待一些有效的错误消息详细信息,例如“身份验证失败”或其他内容
我刚刚体验了使用带有 React Native 的 AWS 开发工具包将图像上传到 S3 的过程。原来是由 ContentEncoding
参数引起的。
删除该参数“修复”了问题。
在调试并花费大量时间之后,就我而言,问题出在 access_key_id 和 secret_access_key 上,只需仔细检查您的凭据或在可能的情况下生成新的凭据,并确保您在 params 中传递凭据。
生成一个新的访问密钥对我有用。
大多数情况下,它是由于错误的密钥 (AWS_SECRET_ACCESS_KEY) 而发生的。请交叉验证您的 AWS_SECRET_ACCESS_KEY。希望它会工作...
像其他人一样,我也有类似的问题,但在 java sdk v1.1 中。对我来说,以下 2 个修复对我有帮助。
我的对象键看起来像这样 /path/to/obj/。在此,我首先删除了开头的 /。此外,仅第 1 点并不能解决问题。我将我的 sdk 版本从 1.9.x 升级到 1.11.x
应用这两个修复程序后,它起作用了。所以我的建议不是坚持下去。如果没有其他工作,只需尝试升级 lib。
我遇到了类似的错误,但对我来说,这似乎是由于重新使用 IAM 用户在两个不同的 Elastic Beanstalk 环境中使用 S3 造成的。我通过为每个环境创建一个具有相同权限的 IAM 用户来治疗这种症状,这使错误消失了。
我不知道是否有人在尝试在浏览器中测试输出的 URL 时遇到此问题,但如果您使用 Postman
并尝试从 RAW
选项卡复制 AWS 生成的 url,因为转义反斜杠您是会得到上述错误。
使用 Pretty
选项卡复制并粘贴 URL 以查看它是否真的有效。
我最近遇到了这个问题,这个解决方案解决了我的问题。这是为了测试目的,看看您是否真的通过 url 检索数据。
此答案是对那些尝试从 AWS 生成下载、临时链接或通常从 AWS 生成 URL 以供使用的人的参考。
就我而言,在 AWS 签名授权方法中使用邮递员发出请求时,我使用 S3(大写)作为服务名称
这个问题发生在我身上,因为我不小心将 ACCESS_KEY_ID
的值分配给了 SECRET_ACCESS_KEY_ID
。一旦这个问题得到解决,一切正常。
我刚刚遇到这个,我有点不好意思说,这是因为我使用的是 HTTP POST 请求而不是 PUT。
尽管我很尴尬,但我想我会分享,以防它可以节省一个小时的时间。
我在使用 SDK 的共享环境中遇到了这个错误,但是使用相同的密钥/秘密和 aws cli,它工作正常。构建系统脚本在密钥、秘密和会话密钥之后有一个空格,代码也读入了这些空格。所以对我来说,解决方法是调整构建脚本以在使用变量后删除空格。
只是为那些可能会在他们的信用末尾错过那个令人沮丧的隐形空间的人添加这个。
在我的例子中,bucketname 是错误的,它包含了密钥的第一部分(bucketxxx/keyxxx)——签名没有任何问题。
在我的情况下(python)它失败了,因为我在文件中有这两行代码,继承自旧代码
http.client.HTTPConnection._http_vsn = 10 http.client.HTTPConnection._http_vsn_str = 'HTTP/1.0'
+
时,我收到了此错误消息。bucket = "bucketname/something"
而不是bucket = "bucketname"
。这也给出了签名不匹配错误。Content-Type
标头时,我得到了这个