只允许一种身份验证机制;只有X-Amz-Algorithm查询参数..?

时间:2015-07-20 10:36:56

标签: angularjs amazon-s3

我正在尝试向amazonS3预先签名的URL发送PUT请求。即使我只有一个PUT请求,我的请求似乎也会被调用两次。第一个请求返回200 OK,第二个请求返回400 Bad Request

这是我的代码:

var req = {
    method: 'PUT',
    url: presignedUrl,
    headers: {
        'Content-Type': 'text/csv'
    },
    data: <some file in base64 format>
};

$http(req).success(function(result) {
    console.log('SUCCESS!');
}).error(function(error) {
    console.log('FAILED!', error);
});

400 Bad Request更详细的错误:

<?xml version="1.0" encoding="UTF-8"?>
<Error>
   <Code>InvalidArgument</Code>
   <Message>Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter, Signature query string parameter or the Authorization header should be specified</Message>
   <ArgumentName>Authorization</ArgumentName>
   <ArgumentValue>Bearer someToken</ArgumentValue>
   <RequestId>someRequestId</RequestId>
   <HostId>someHostId</HostId>
</Error>

我不明白的是,为什么它会回归400?什么是解决方法?

7 个答案:

答案 0 :(得分:19)

您的客户端可能正在发送使用Authorization标头的初始请求,该标头正在使用302进行响应。响应包括具有Signature参数的Location标头。问题是初始请求中的标头被复制到后续重定向请求中,因此它包含授权和签名。如果您从后续请求中删除授权,那么您应该是好的。

这发生在我身上,但是在Java / HttpClient环境中。我可以在Java中提供解决方案的详细信息,但遗憾的是不能用于AngularJS。

答案 1 :(得分:1)

我知道这可能为时已晚,无法回答,但就像@mlohbihler所说的那样,对我来说这个错误的原因是我在Angular中设置的http拦截器发送的Authorization标头。 基本上,我没有正确地过滤掉AWS S3域,以避免它自动获取JWT授权头。

答案 2 :(得分:1)

此外,400“无效参数”可能表示由于您的S3 :: Presigner的配置/凭据错误而导致该URL开始处于预设状态。一旦超过400,您可能会遇到像我一样的501“未实现”的响应。能够通过指定Content-Length标头(指定here作为必需标头)来解决它。希望这有助于@arjuncc,它在使用预签名网址测试s3图片上传时解决了我的邮递员问题。

答案 3 :(得分:1)

对于Google员工,如果您通过Cloudfront发送已签名的(签名v4)S3请求,并且在Cloudfront Origin设置中将“限制存储桶访问”设置为“是”,则Cloudfront会将Authorization标头添加到您的请求中,您会收到此错误。不过,由于您已经签署了请求,因此应该可以关闭此设置,而不必牺牲任何安全性。

答案 4 :(得分:0)

该消息表明仅允许一次身份验证。可能是您发送的一个是带有auth参数的url,另一个是授权标头。

答案 5 :(得分:0)

import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:scavenger_inc_flutter/utils/AuthUtils.dart';
import 'package:scavenger_inc_flutter/utils/URLS.dart';

class ApiClient {
  static Dio dio;

  static Dio getClient() {
    if (dio == null) {
      dio = new Dio();
      dio.httpClientAdapter = new CustomHttpAdapter();
    }
    return dio;
  }
}

class CustomHttpAdapter extends HttpClientAdapter {
  DefaultHttpClientAdapter _adapter = DefaultHttpClientAdapter();

  @override
  void close({bool force = false}) {
    _adapter.close(force: force);
  }

  @override
  Future<ResponseBody> fetch(RequestOptions options,
      Stream<List<int>> requestStream, Future<dynamic> cancelFuture) async {
    String url = options.uri.toString();
    if (url.contains(URLS.IP_ADDRESS) && await AuthUtils.isLoggedIn()) {
      options.followRedirects = false;
      options.headers.addAll({"Authorization": await AuthUtils.getJwtToken()});
    }
    final response = await _adapter.fetch(options, requestStream, cancelFuture);

    if (response.statusCode == 302 || response.statusCode == 307) {
      String redirect = (response.headers["location"][0]);
      if(!redirect.contains(URLS.IP_ADDRESS)) {
        options.path = redirect;
        options.headers.clear();
      }
      return await fetch(options, requestStream, cancelFuture);
    }

    return response;
  }
}
  1. 我不允许进行重定向。

  2. 使用响应对象检查它是否已重定向。

  3. 如果它是302或307(HTTP重定向代码),我在清除身份验证标头后会重新发送请求。

  4. 仅当路径包含我的特定域URL(在此示例中为IP地址)时,我才使用附加检查发送标头。

以上所有方法,都使用Dio中的CustomHttpAdapter。通过将ResponseType更改为字节,也可以用于图像。

让我知道这是否对您有帮助!

答案 6 :(得分:0)

我使用的是 django restframework。我在 REST API 中应用了令牌身份验证。我曾经在 django API 的请求头中传递令牌(使用了浏览器的 ModHeader 扩展,它自动将令牌放入请求头的授权中),直到这里一切正常。

但是在点击图像/文件(现在显示 s3 URL)时。授权自动通过。因此,问题。

链接看起来与此类似。

https://.s3.amazonaws.com/media//small_image.jpg?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Credential=XXXXXXXXXXXXXXXXXXXXX%2F20210317%2Fap-south-XXXXXXXXFaws4_request&X-Amz-Date=XXXXXXXXXXXXXXX&X-Amz-Expires=3600&X-Amz-SignedHeaders=host&X-Amz-Signature=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

我锁定 ModHeader 扩展以仅在对 REST API 进行休息时而不是在对 S3 资源进行请求时传递授权令牌。即在向 S3 资源发出请求时不要传递任何其他授权。

这是一个愚蠢的错误。但万一有帮助。