HttpWebRequests发送参数的URI的授权头 [英] HttpWebRequests sends parameterless URI in Authorization header

查看:202
本文介绍了HttpWebRequests发送参数的URI的授权头的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我连接到从.NET,像Web服务:

I'm connecting to a web service from .NET, like:

var request = (HttpWebRequest) WebRequest.Create(uri);
request.Credentials = new NetworkCredential("usr", "pwd", "domain");
var response = (HttpWebResponse) request.GetResponse();

Authorization头看起来像:

The authorization header looks like:

Authorization: Digest username="usr",realm="domain",nonce="...",
    uri="/dir",algorithm="MD5",etc...
    ^^^^^^^^^^

服务器将返回(400)错误的请求。通过Chrome或IE浏览器发送一个报头是这样的:

The server returns (400) Bad Request. A header send by Chrome or IE looks like:

Authorization: Digest username="usr", realm="domain", nonce="...", 
    uri="/dir/query?id=1", algorithm=MD5, etc...
    ^^^^^^^^^^^^^^^^^^^^^

我们怀疑,在URI的不同引起了Web服务拒绝与一个400错误的请求。是否有可能使Htt的prequest发送Authorization头,其中包括完整的URI?

We suspect that the difference in URI is causing the web service to deny the request with a 400 error. Is it possible to make HttpRequest send out an Authorization header that includes the full URI?

推荐答案

原来,摘要式身份验证是相当容易实现。凭借我们自己的实现,我们可以使用完整的URI(包括参数)来生成MD5哈希值。这解决了问题。

It turns out that Digest authentication is fairly easy to implement. With our own implementation, we were able to use the full URI (including parameters) to generate the MD5 hash. That fixed the problem.

在有人的情况下,未来打这个问题,你可以调用类的解决方法:

In case someone hits this problem in the future, you can call the workaround like:

var resultText = DigestAuthFixer.GrabResponse("/dir/index.html");

在code为DigestAuthFixer类:

The code for the DigestAuthFixer class:

public static class DigestAuthFixer
{
    private static string _host = "http://localhost";
    private static string _user = "Mufasa";
    private static string _password = "Circle Of Life";
    private static string _realm;
    private static string _nonce;
    private static string _qop;
    private static string _cnonce;
    private static DateTime _cnonceDate;
    private static int _nc;

    private static string CalculateMd5Hash(
        string input)
    {
        var inputBytes = Encoding.ASCII.GetBytes(input);
        var hash = MD5.Create().ComputeHash(inputBytes);
        var sb = new StringBuilder();
        foreach (var b in hash)
            sb.Append(b.ToString("x2"));
        return sb.ToString();
    }

    private static string GrabHeaderVar(
        string varName,
        string header)
    {
        var regHeader = new Regex(string.Format(@"{0}=""([^""]*)""", varName));
        var matchHeader = regHeader.Match(header);
        if (matchHeader.Success)
            return matchHeader.Groups[1].Value;
        throw new ApplicationException(string.Format("Header {0} not found", varName));
    }

    // http://en.wikipedia.org/wiki/Digest_access_authentication
    private static string GetDigestHeader(
        string dir)
    {
        _nc = _nc + 1;

        var ha1 = CalculateMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
        var ha2 = CalculateMd5Hash(string.Format("{0}:{1}", "GET", dir));
        var digestResponse =
            CalculateMd5Hash(string.Format("{0}:{1}:{2:00000000}:{3}:{4}:{5}", ha1, _nonce, _nc, _cnonce, _qop, ha2));

        return string.Format("Digest username=\"{0}\", realm=\"{1}\", nonce=\"{2}\", uri=\"{3}\", " +
            "algorithm=MD5, response=\"{4}\", qop={5}, nc={6:00000000}, cnonce=\"{7}\"",
            _user, _realm, _nonce, dir, digestResponse, _qop, _nc, _cnonce);
    }

    public static string GrabResponse(
        string dir)
    {
        var url = _host + dir;
        var uri = new Uri(url);

        var request = (HttpWebRequest)WebRequest.Create(uri);

        // If we've got a recent Auth header, re-use it!
        if (!string.IsNullOrEmpty(_cnonce) &&
            DateTime.Now.Subtract(_cnonceDate).TotalHours < 1.0)
        {
            request.Headers.Add("Authorization", GetDigestHeader(dir));
        }

        HttpWebResponse response;
        try
        {
            response = (HttpWebResponse)request.GetResponse();
        }
        catch (WebException ex)
        {
            // Try to fix a 401 exception by adding a Authorization header
            if (ex.Response == null || ((HttpWebResponse)ex.Response).StatusCode != HttpStatusCode.Unauthorized)
                throw;

            var wwwAuthenticateHeader = ex.Response.Headers["WWW-Authenticate"];
            _realm = GrabHeaderVar("realm", wwwAuthenticateHeader);
            _nonce = GrabHeaderVar("nonce", wwwAuthenticateHeader);
            _qop = GrabHeaderVar("qop", wwwAuthenticateHeader);

            _nc = 0;
            _cnonce = new Random().Next(123400, 9999999).ToString();
            _cnonceDate = DateTime.Now;

            var request2 = (HttpWebRequest)WebRequest.Create(uri);
            request2.Headers.Add("Authorization", GetDigestHeader(dir));
            response = (HttpWebResponse)request2.GetResponse();
        }
        var reader = new StreamReader(response.GetResponseStream());
        return reader.ReadToEnd();
    }
}

这篇关于HttpWebRequests发送参数的URI的授权头的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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