【问题标题】:Only one auth mechanism allowed; only the X-Amz-Algorithm query parameter..?只允许一种身份验证机制;只有 X-Amz-Algorithm 查询参数..?
【发布时间】:2015-10-09 10:45:21
【问题描述】:

我正在尝试向 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?以及解决方法是什么?

【问题讨论】:

  • 我会调查为什么它被调用两次,因为第一次看起来工作正常
  • 你找到解决办法了吗?
  • 如果您想调用 s3 url,只需在调用之前删除您在应用中用于任何其他 API 的所有授权标头。

标签: angularjs amazon-s3


【解决方案1】:

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

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

【讨论】:

  • 如果您可以将解决方案的详细信息粘贴到 Java 中,那就太好了……只是遇到了同样的问题。
  • 不幸的是,代码被替换为访问 S3 的替代方式(通过应用程序服务器而不是直接流式传输),所以我不再拥有它了。但基本上你在将它们应用到后续请求之前访问响应标头并删除授权。
  • 这个很有帮助。我在邮递员中遇到了同样的问题。有什么办法解决吗
  • @mlohbihler 你还有java解决方案的细节吗??我遇到与 apache HttpClient 相同的问题
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    【讨论】:

      【解决方案4】:

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

      【讨论】:

        【解决方案5】:

        消息说只允许一次身份验证。可能是您在 URL 中发送一个作为身份验证参数,另一个 - 在标头中作为授权标头。

        【讨论】:

          【解决方案6】:
          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 重定向代码),我会在清除 Auth Headers 后重新发送请求。

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

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

          如果这对您有帮助,请告诉我!

          【讨论】:

            【解决方案7】:

            我使用的是 django restframework。我在 REST API 中应用了 Token authentication。我使用在 django API 的请求标头中传递令牌(使用 ModHeader 浏览器的扩展,它自动将令牌放入请求标头的授权中)直到这里一切都很好。

            但是在点击 Images/Files(现在显示 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 资源发出请求时不要传递任何其他授权。

            这是一个愚蠢的错误。但以防万一。

            【讨论】:

              猜你喜欢
              • 2019-01-03
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2015-05-16
              • 1970-01-01
              • 2017-02-19
              • 2020-03-10
              • 2016-11-02
              相关资源
              最近更新 更多