重定向时授权标头丢失 [英] Authorization header is lost on redirect

查看:86
本文介绍了重定向时授权标头丢失的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下是进行身份验证、生成授权标头和调用 API 的代码.

Below is the code that does authentication, generates the Authorization header, and calls the API.

不幸的是,在 API 上的 GET 请求之后,我收到了 401 Unauthorized 错误.

Unfortunately, I get a 401 Unauthorized error following the GET request on the API.

但是,当我在 Fiddler 中捕获流量并重放它时,对 API 的调用成功并且我可以看到所需的 200 OK 状态代码.

However, when I capture the traffic in Fiddler and replay it, the call to the API is successful and I can see the desired 200 OK status code.

[Test]
public void RedirectTest()
{
    HttpResponseMessage response;
    var client = new HttpClient();
    using (var authString = new StringContent(@"{username: ""theUser"", password: ""password""}", Encoding.UTF8, "application/json"))
    {
        response = client.PostAsync("http://host/api/authenticate", authString).Result;
    }

    string result = response.Content.ReadAsStringAsync().Result;
    var authorization = JsonConvert.DeserializeObject<CustomAutorization>(result);
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authorization.Scheme, authorization.Token);
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.host+json;version=1");

    response =
        client.GetAsync("http://host/api/getSomething").Result;
    Assert.True(response.StatusCode == HttpStatusCode.OK);
}

当我运行此代码时,授权标头丢失.

When I run this code the Authorization header is lost.

但是,在 Fiddler 中,标头成功传递.

However, in Fiddler that header is passed successfully.

知道我做错了什么吗?

推荐答案

您遇到这种行为的原因是设计.

The reason you are experiencing this behavior is that it is by design.

大多数 HTTP 客户端(默认情况下)在遵循重定向时去除授权标头.

Most HTTP clients (by default) strip out authorization headers when following a redirect.

一个原因是安全.客户端可能会被重定向到不受信任的第三方服务器,您不想向其透露您的授权令牌.

One reason is security. The client could be redirected to an untrusted third party server, one that you would not want to disclose your authorization token to.

你可以做的是检测到重定向已经发生,然后直接将请求重新发送到正确的位置.

What you can do is detect that the redirect has occurred and reissue the request directly to the correct location.

您的 API 返回 401 Unauthorized 表示授权标头丢失(或不完整).如果授权信息存在于请求中但完全不正确(错误的用户名/密码),我将假设相同的 API 返回 403 Forbidden.

Your API is returning 401 Unauthorized to indicate that the authorization header is missing (or incomplete). I will assume that the same API returns 403 Forbidden if the authorization information is present in the request but is simply incorrect (wrong username / password).

如果是这种情况,您可以检测重定向/缺少授权标头"组合并重新发送请求.

If this is the case, you can detect the 'redirect / missing authorization header' combination and resend the request.

这是为了执行此操作而重写的问题中的代码:

Here is the code from the question rewritten to do this:

[Test]
public void RedirectTest()
{
    // These lines are not relevant to the problem, but are included for completeness.
    HttpResponseMessage response;
    var client = new HttpClient();
    using (var authString = new StringContent(@"{username: ""theUser"", password: ""password""}", Encoding.UTF8, "application/json"))
    {
        response = client.PostAsync("http://host/api/authenticate", authString).Result;
    }

    string result = response.Content.ReadAsStringAsync().Result;
    var authorization = JsonConvert.DeserializeObject<CustomAutorization>(result);

    // Relevant from this point on.
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authorization.Scheme, authorization.Token);
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.host+json;version=1");

    var requestUri = new Uri("http://host/api/getSomething");
    response = client.GetAsync(requestUri).Result;

    if (response.StatusCode == HttpStatusCode.Unauthorized)
    {
        // Authorization header has been set, but the server reports that it is missing.
        // It was probably stripped out due to a redirect.

        var finalRequestUri = response.RequestMessage.RequestUri; // contains the final location after following the redirect.

        if (finalRequestUri != requestUri) // detect that a redirect actually did occur.
        {
            if (IsHostTrusted(finalRequestUri)) // check that we can trust the host we were redirected to.
            {
               response = client.GetAsync(finalRequestUri).Result; // Reissue the request. The DefaultRequestHeaders configured on the client will be used, so we don't have to set them again.
            }
        }
    }

    Assert.True(response.StatusCode == HttpStatusCode.OK);
}


private bool IsHostTrusted(Uri uri)
{
    // Do whatever checks you need to do here
    // to make sure that the host
    // is trusted and you are happy to send it
    // your authorization token.

    if (uri.Host == "host")
    {
        return true;
    }

    return false;
}

<小时>

请注意,您可以保存 finalRequestUri 的值并将其用于未来的请求,以避免重试中涉及的额外请求.但是,由于这是一个临时重定向,您可能应该每次都向原始位置发出请求.


Note that you could save the value of finalRequestUri and use it for future requests to avoid the extra request involved in the retry. However as this is a temporary redirect you should probably issue the request to the original location each time.

这篇关于重定向时授权标头丢失的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆