Django Rest Framework:使用令牌身份验证时,重定向到Amazon S3失败

Clo*_*ans 5 python django amazon-s3 http-headers django-rest-framework

我在DRF中使用令牌身份验证,对于某个API调用,想要重定向到S3(使用类似的URL https://my_bucket.s3.amazonaws.com/my/file/path/my_file.jpg?Signature=MY_AWS_SIGNATURE&AWSAccessKeyId=MY_AWS_ACCESS_KEY_ID).但是,我从AWS收到以下错误:

<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>Token a3f61c10592272399099882eb178bd4b755af5bf</ArgumentValue>
  <RequestId>E4038228DD1E6330</RequestId>
  <HostId>9c2xX59cugrR0CHjxQJR8IBE4MXBbNMX+wX2JdPJEuerkAftc32rufotM7COKLIavakByuRUXOo=</HostId>
</Error>
Run Code Online (Sandbox Code Playgroud)

很清楚为什么会发生这种情况 - Authorization带有DRF令牌的标头会随着重定向传播而S3不喜欢它.

在研究并尝试了一百万种方法来摆脱那个标题之后,我放弃了并决定尝试用S3值覆盖标题:AWS MY_AWS_SIGNATURE:MY_AWS_ACCESS_KEY_ID之后我得到了一个不同的错误:

<Error>
  <Code>InvalidArgument</Code>
  <Message>Unsupported Authorization Type</Message>
  <ArgumentName>Authorization</ArgumentName>
  <ArgumentValue>Token a3f61c10592272399099882eb178bd4b755af5bf</ArgumentValue>
  <RequestId>94D5ADA28C6A5BFB</RequestId>
  <HostId>1YznL6UC3V0+nCvilsriHDAnP2/h3MoDlIJ/L+0V6w7nbHbf2bSxoQflujGmQ5PrUZpNiH7GywI=</HostId>
</Error>
Run Code Online (Sandbox Code Playgroud)

如您所见,最终结果是相同的 - 即使我Authorization在响应中覆盖标头,它仍保留原始DRF令牌身份验证值.

# relevant portion of my response construction
headers = {'Location': 'https://my_bucket.s3.amazonaws.com/my/file/path/my_file.jpg',
           'Authorization': 'AWS %s:%s' % (params['AWSAccessKeyId'], params['Signature'])}
return Response(status=status.HTTP_302_FOUND, headers=headers)
Run Code Online (Sandbox Code Playgroud)

所以,我的问题是,如何Authorization删除或覆盖DRF响应中的标头?

Léo*_*Léo 4

重定向Authorization标头是客户端的责任(例如浏览器、cURL、HTTP 库/工具包)。

例如,我的 API 查询工具包 Paw 提供了这种配置: Paw 应用程序重定向配置

所以基本上,主流浏览器倾向于重定向Authorization标头,这会导致 S3 上的冲突。

我还怀疑您误解了重定向的执行方式:

  1. 当 DRF 发出重定向时,它会HTTP 301 or 302向客户端返回一个响应,其中包含新Location标头(请求不会直接通过 DRF“转发”)
  2. 然后,客户端请求这个新的 URI

最后,Authorization当您发出请求时,您不会覆盖任何标头,302因为这是对客户端的响应(可以携带标Authorization头,但毫无用处)。


现在,您有很多解决方案(因此不是开箱即用的......):

  1. 通过不同的标头传递您的令牌以避免冲突(例如 X-Token)
  2. 通过参数传递您的令牌HTTP GET( ?token=blah)
  3. 使用 DRF 视图代理 S3 对象(则无需重定向)

前两种解决方案可能会在某种程度上破坏 API 的一致性,但在某种程度上是足够公平的。他们需要定制TokenAuthenticationget_authorization_header(来自rest_framework.authorization)。

最后一个是透明的,但可能完全不合适,具体取决于您在 S3 上获取的对象和/或您的托管限制...

目前我能告诉你的就是这些。如你所知,我也遇到过同样的情况。如果有人能提出更好的解决方案,我会很高兴。