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

时间:2023-02-11 23:07:17

I'm using token authentication in DRF and for a certain API call, want to redirect to S3 (using a URL like https://my_bucket.s3.amazonaws.com/my/file/path/my_file.jpg?Signature=MY_AWS_SIGNATURE&AWSAccessKeyId=MY_AWS_ACCESS_KEY_ID). However, I get the following error from AWS:

我在DRF和某个API调用中使用令牌身份验证,想要重定向到S3(使用像https://my_bucket.s3.amazonaws.com/my/file/path/my_file.jpg?Signature=MY_AWS_SIGNATURE&AWSAccessKeyId这样的URL = 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>

It's clear why this happens--the Authorization header with DRF's token is propagated with the redirect and S3 doesn't like it.

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

After researching and trying a million ways to get rid of that header, I gave up and decided to try and override the header with an S3 value: AWS MY_AWS_SIGNATURE:MY_AWS_ACCESS_KEY_ID, after which I get a different error:

在研究并尝试了一百万种方法来摆脱那个标题后,我放弃了并决定尝试用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>

As you can see, the end result is the same--even if I override the Authorization header in my response, it still keeps the original DRF token authentication value.

如您所见,最终结果是相同的 - 即使我在响应中覆盖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)

So, my question is, how can the Authorization header in a DRF response be either removed or overridden?

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

1 个解决方案

#1


3  

Redirecting the Authorization header is the responsibility of the client (eg. browsers, cURL, HTTP libraries/toolkits).

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

For example, Paw, my toolkit to query my APIs offers that kind of configuration: Django Rest Framework:使用令牌身份验证时重定向到Amazon S3失败

例如,Paw,我查询我的API的工具包提供了这样的配置:

So basically, major browsers are tend to redirect the Authorization header which cause the conflict on S3.

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

Also I suspect you misunderstood how redirects are performed:

另外我怀疑你误解了重定向的执行方式:

  1. When DRF issues a redirect, it returns an HTTP 301 or 302 response to the client, containing the new Location header (the request is not "forwarded" directly via DRF)
  2. 当DRF发出重定向时,它会向客户端返回HTTP 301或302响应,其中包含新的Location头(请求不是直接通过DRF“转发”)

  3. Then, the client requests this new URI
  4. 然后,客户端请求此新URI

And finally, you're not overriding any Authorization header when you're emitting your 302 since this is the response... to the client (which can carry an Authorization header but that's useless).

最后,当你发出302时,你没有覆盖任何授权标题,因为这是对客户端的响应...(它可以带有授权标题但是没用)。


Right now, you have a bunch of solutions (thus not out of the box...):

现在,你有一堆解决方案(因此没有开箱即用......):

  1. Passing your token through a different header to avoid the conflict (X-Token for example)
  2. 将令牌传递到不同的标头以避免冲突(例如X-Token)

  3. Passing your token through a HTTP GET parameter (?token=blah)
  4. 通过HTTP GET参数传递令牌(?token = blah)

  5. Using your DRF view to proxy the S3 object (no redirect then)
  6. 使用DRF视图代理S3对象(无重定向)

The first two solutions may break in some way the consistency of your API but in some way are fair enough. They would require a custom TokenAuthentication or get_authorization_header (from rest_framework.authorization).

前两个解决方案可能会以某种方式破坏API的一致性,但在某种程度上是公平的。他们需要自定义TokenAuthentication或get_authorization_header(来自rest_framework.authorization)。

The last one is transparent but may be totally unsuitable depending on the object your're fetching on S3 and/or your hosting constraints...

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

That's all I can tell you for now. As you know, I've been stuck with the same situation too. I would be so pleased if anyone could suggest a better solution.

这就是我现在可以告诉你的全部内容。如你所知,我也一直陷入同样的​​境地。如果有人能提出更好的解决方案,我会很高兴。

#1


3  

Redirecting the Authorization header is the responsibility of the client (eg. browsers, cURL, HTTP libraries/toolkits).

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

For example, Paw, my toolkit to query my APIs offers that kind of configuration: Django Rest Framework:使用令牌身份验证时重定向到Amazon S3失败

例如,Paw,我查询我的API的工具包提供了这样的配置:

So basically, major browsers are tend to redirect the Authorization header which cause the conflict on S3.

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

Also I suspect you misunderstood how redirects are performed:

另外我怀疑你误解了重定向的执行方式:

  1. When DRF issues a redirect, it returns an HTTP 301 or 302 response to the client, containing the new Location header (the request is not "forwarded" directly via DRF)
  2. 当DRF发出重定向时,它会向客户端返回HTTP 301或302响应,其中包含新的Location头(请求不是直接通过DRF“转发”)

  3. Then, the client requests this new URI
  4. 然后,客户端请求此新URI

And finally, you're not overriding any Authorization header when you're emitting your 302 since this is the response... to the client (which can carry an Authorization header but that's useless).

最后,当你发出302时,你没有覆盖任何授权标题,因为这是对客户端的响应...(它可以带有授权标题但是没用)。


Right now, you have a bunch of solutions (thus not out of the box...):

现在,你有一堆解决方案(因此没有开箱即用......):

  1. Passing your token through a different header to avoid the conflict (X-Token for example)
  2. 将令牌传递到不同的标头以避免冲突(例如X-Token)

  3. Passing your token through a HTTP GET parameter (?token=blah)
  4. 通过HTTP GET参数传递令牌(?token = blah)

  5. Using your DRF view to proxy the S3 object (no redirect then)
  6. 使用DRF视图代理S3对象(无重定向)

The first two solutions may break in some way the consistency of your API but in some way are fair enough. They would require a custom TokenAuthentication or get_authorization_header (from rest_framework.authorization).

前两个解决方案可能会以某种方式破坏API的一致性,但在某种程度上是公平的。他们需要自定义TokenAuthentication或get_authorization_header(来自rest_framework.authorization)。

The last one is transparent but may be totally unsuitable depending on the object your're fetching on S3 and/or your hosting constraints...

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

That's all I can tell you for now. As you know, I've been stuck with the same situation too. I would be so pleased if anyone could suggest a better solution.

这就是我现在可以告诉你的全部内容。如你所知,我也一直陷入同样的​​境地。如果有人能提出更好的解决方案,我会很高兴。