Подпись Amazon S3 не соответствует - AWS SDK Java
У меня есть приложение для воспроизведения, которое должно загружать файлы на S3. Мы разрабатываем в Scala и используем Java AWS SDK.
У меня возникают проблемы при загрузке файлов, я продолжаю получать 403 SignatureDoesNotMatch при использовании предварительно назначенных URL-адресов. URL создается с использованием AWS Java SDK с помощью следующего кода:
def generatePresignedPutRequest(filename: String) = {
val expiration = new java.util.Date();
var msec = expiration.getTime() + 1000 * 60 * 60; // Add 1 hour.
expiration.setTime(msec);
s3 match {
case Some(s3) => s3.generatePresignedUrl(bucketname, filename, expiration, HttpMethod.PUT).toString
case None => {
Logger.warn("S3 is not availiable. Cannot generate PUT request.")
"URL not availiable"
}
}
}
За кодом веб- интерфейса мы следовали статье об ионных пушках.
Функция js, которая загружает файл (такая же, как та, которая использовалась в статье)
function uploadToS3(file, url)
{
var xhr = createCORSRequest('PUT', url);
if (!xhr)
{
setProgress(0, 'CORS not supported');
}
else
{
xhr.onload = function()
{
if(xhr.status == 200)
{
setProgress(100, 'Upload completed.');
}
else
{
setProgress(0, 'Upload error: ' + xhr.status);
}
};
xhr.onerror = function()
{
setProgress(0, 'XHR error.');
};
xhr.upload.onprogress = function(e)
{
if (e.lengthComputable)
{
var percentLoaded = Math.round((e.loaded / e.total) * 100);
setProgress(percentLoaded, percentLoaded == 100 ? 'Finalizing.' : 'Uploading.');
}
};
xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('x-amz-acl', 'authenticated-read');
xhr.send(file);
}
}
Ответ сервера
<?xml version="1.0" encoding="UTF-8"?>
<Error><Code>SignatureDoesNotMatch</Code>
<Message>The request signature we calculated does not match the signature you provided. Check your key and signing method.</Message>
<StringToSignBytes>50 55 bla bla bla...</StringToSignBytes>
<RequestId>F7A8F1659DE5909C</RequestId>
<HostId>q+r+2T5K6mWHLKTZw0R9/jm22LyIfZFBTY8GEDznfmJwRxvaVJwPiu/hzUfuJWbW</HostId>
<StringToSign>PUT
image/png
1387565829
x-amz-acl:authenticated-read
/mybucketname/icons/f5430c16-32da-4315-837f-39a6cf9f47a1</StringToSign>
<AWSAccessKeyId>myaccesskey</AWSAccessKeyId></Error>
Я настроил CORS, дважды проверил учетные данные aws и попытался изменить заголовки запросов. Я всегда получаю один и тот же результат. Почему Amazon говорит мне, что подписи не совпадают?
5 ответов
Сомневаюсь, что у ОП все еще есть проблема с этим, но для всех, кто сталкивается с этим, вот ответ:
Делая подписанный запрос к S3, AWS проверяет, чтобы убедиться, что подпись точно соответствует информации заголовка HTTP, отправленной браузером. К сожалению, это необходимо прочитать: http://s3.amazonaws.com/doc/s3-developer-guide/RESTAuthentication.html
Однако в приведенном выше коде это не совсем так, Javascript отправляет:
xhr.setRequestHeader('Content-Type', 'image/png');
xhr.setRequestHeader('x-amz-acl', 'authenticated-read');
Но в Java/Scala s3.generatePresignedUrl вызывается без передачи в любой из них. Таким образом, получающаяся подпись фактически говорит S3 отклонить что-либо с набором заголовков Content-Type или x-ams-acl. Упс (я тоже за это влюбился).
Я видел, как браузеры автоматически отправляют Content-Types, поэтому, даже если они явно не добавлены в заголовок, они все равно могут попасть в S3. Итак, вопрос в том, как добавить заголовки Content-Type и x-amz-acl в подпись?
В AWS SDK есть несколько перегруженных функций generatePresignedUrl, но только одна из них позволяет нам передавать что-либо еще, кроме имени корзины, имени файла, даты окончания срока действия и метода http.
Решение:
- Создайте объект GeneratePresignedUrlRequest с вашим бакетом и именем файла.
- Вызовите setExpiration, setContentType и т. Д., Чтобы установить для него всю информацию заголовка.
- Передайте это в s3.generatePresignedUrl как единственный параметр.
Вот правильное определение функции GeneratePresignedUrlRequest для использования:
http://docs.aws.amazon.com/AWSJavaSDK/latest/javadoc/com/amazonaws/services/s3/AmazonS3Client.html
Код функции в репозитории AWS GitHub также помог мне понять, как кодировать решение. Надеюсь это поможет.
Я столкнулся с похожей проблемой и настройкой конфига signatureVersion: 'v4'
помог решить это в моем случае -
В JavaScript:
var s3 = new AWS.S3({
signatureVersion: 'v4'
});
Адаптировано с https://github.com/aws/aws-sdk-js/issues/902
Я только что столкнулся с этой проблемой, используя NodeJs AWS SDK. Это было связано с использованием учетных данных, которые были действительны, но без достаточных разрешений. Изменение в моем ключе администратора исправило это без изменений кода!
У меня была такая же проблема, но удаление типа контента работает нормально. Настоящим делюсь полным кодом.
public class GeneratePresignedUrlAndUploadObject {
private static final String BUCKET_NAME = "<YOUR_AWS_BUCKET_NAME>";
private static final String OBJECT_KEY = "<YOUR_AWS_KEY>";
private static final String AWS_ACCESS_KEY = "<YOUR_AWS_ACCESS_KEY>";
private static final String AWS_SECRET_KEY = "<YOUR_AWS_SECRET_KEY>";
public static void main(String[] args) throws IOException {
BasicAWSCredentials awsCreds = new BasicAWSCredentials(AWS_ACCESS_KEY, AWS_SECRET_KEY);
AmazonS3 s3Client = AmazonS3ClientBuilder.standard().withRegion(Regions.US_EAST_1)
.withCredentials(new AWSStaticCredentialsProvider(awsCreds)).build();
try {
System.out.println("Generating pre-signed URL.");
java.util.Date expiration = new java.util.Date();
long milliSeconds = expiration.getTime();
milliSeconds += 1000 * 60 * 60;
expiration.setTime(milliSeconds);
GeneratePresignedUrlRequest generatePresignedUrlRequest =
new GeneratePresignedUrlRequest(BUCKET_NAME, OBJECT_KEY);
generatePresignedUrlRequest.setMethod(HttpMethod.PUT);
generatePresignedUrlRequest.setExpiration(expiration);
URL url = s3Client.generatePresignedUrl(generatePresignedUrlRequest);
UploadObject(url);
System.out.println("Pre-Signed URL = " + url.toString());
} catch (AmazonServiceException exception) {
System.out.println("Caught an AmazonServiceException, " +
"which means your request made it " +
"to Amazon S3, but was rejected with an error response " +
"for some reason.");
System.out.println("Error Message: " + exception.getMessage());
System.out.println("HTTP Code: " + exception.getStatusCode());
System.out.println("AWS Error Code:" + exception.getErrorCode());
System.out.println("Error Type: " + exception.getErrorType());
System.out.println("Request ID: " + exception.getRequestId());
} catch (AmazonClientException ace) {
System.out.println("Caught an AmazonClientException, " +
"which means the client encountered " +
"an internal error while trying to communicate" +
" with S3, " +
"such as not being able to access the network.");
System.out.println("Error Message: " + ace.getMessage());
}
}
public static void UploadObject(URL url) throws IOException
{
HttpURLConnection connection=(HttpURLConnection) url.openConnection();
connection.setDoOutput(true);
connection.setRequestMethod("PUT");
OutputStreamWriter out = new OutputStreamWriter(
connection.getOutputStream());
out.write("This text uploaded as object.");
out.close();
int responseCode = connection.getResponseCode();
System.out.println("Service returned response code " + responseCode);
}
}
У меня такая же проблема, но по другой причине. Я использовал POST вместо PUT
Если ваши ключи доступа и секретные ключи хороши, но написано "SignatureDoesNotMAtch", проверьте свой секретный ключ, он, вероятно, имеет какие-либо специальные символы, например +/ - / *
Перейдите в aws и сгенерируйте другой ключ доступа, где секретный ключ не имеет их. Тогда попробуйте еще раз:)
Я столкнулся с SignatureDoesNotMatch
ошибка с использованием Java AWS SDK
. В моем случае,SignatureDoesNotMatch
ошибка произошла после обновленных зависимостей maven без изменений в моем коде (поэтому учетные данные верны и не были изменены). После обновления зависимостиorg.apache.httpcomponents:httpclient
из версии 4.5.6
к 4.5.7
(на самом деле это была модернизация Spring Boot
от 2.1.2
к 2.1.3
, и там bom
указал httpclient
версия), код стал исключать исключения при выполнении некоторых запросов AWS SDK S3, например AmazonS3.getObject
.
Покопавшись в основной причине, я обнаружил, что httpclient
библиотека внесла критические изменения с нормализованным URI, которые затронули Java AWS SDK S3. Пожалуйста, обратите внимание на открытый билет GitHub org.apache.httpcomponents:httpclient:4.5.7 прерывает получение объектов S3 для получения более подробной информации.
Возникла проблема, MIME-тип в Windows устанавливал для fileType пустую строку, и он не работал. Просто обработайте пустые строки и добавьте тип файла.