簡體   English   中英

帶參數的HTTP摘要認證

[英]HTTP Digest Authentication with Parameters

我們正在嘗試使用摘要身份驗證連接到WebService。 只要我在uri中沒有任何參數,它就可以正常工作。 我幾天以來一直在尋找解決方案。

我還嘗試了很多示例,例如:
http://blogs.msdn.com/b/daniem/archive/2013/02/27/digest-authentication-in-system-net-classes-not-compatible-with-rfc2617.aspx

但是我總是得到401未經授權。

請參閱隨附的代碼:

private string WebServiceCall(string methodname)
    {
        try
        {
            string response = string.Empty;

            Uri uri = new Uri(string.Format("http://{0}:{1}/{2}", servername, port, methodname));
            UriBuilder builder = new UriBuilder(uri);
            var query = HttpUtility.ParseQueryString(builder.Query);
            query["fields"] = "posgood";
            builder.Query = query.ToString();
            uri = builder.Uri;

            WebProxy proxy = new WebProxy(uri, true);

            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
            webRequest.Method = "GET";
            webRequest.Proxy = proxy;
            webRequest.PreAuthenticate = true;
            webRequest.AllowAutoRedirect = true;
            CredentialCache cache = new CredentialCache();
            cache.Add(new Uri(string.Format("http://{0}:{1}/{2}", servername, port, methodname)), "Digest", new NetworkCredential("myUser", "myPassowrd", "Ekahau RTLS Controller"));
            webRequest.Credentials = cache;


            using (HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse())
            using (Stream responseStream = webResponse.GetResponseStream())
            {
                if (responseStream != null)
                {
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        response = streamReader.ReadToEnd();
                    }
                }
            }
            return response;
        }
        catch (Exception caught)
        {
            throw new Exception(string.Format("Exception in WebServiceCall: {0}", caught.Message));
        }
    }

如果您對UriBuilder部分不滿意,則可以正常工作。
我也嘗試使用具有相同結果的HttpClient.GetAsync()方法。

編輯1:
不帶參數的Uri:172.16.24.51:8550 / epe / pos / taglist
具有參數的Uri:172.16.24.51:8550 / epe / pos / taglist?fields = posgood

我找到了一個修改類的答案:
http://blogs.msdn.com/b/daniem/archive/2013/02/27/digest-authentication-in-system-net-classes-not-compatible-with-rfc2617.aspx

/// <summary>
/// Modified class from:
/// http://blogs.msdn.com/b/daniem/archive/2013/02/27/digest-authentication-in-system-net-classes-not-compliant-with-rfc2617.aspx
/// 
/// Added parameter: opaque
/// Removed parameter: md5, Alogrithm (no md5 algorithm in answer)
/// </summary>
public class DigestHttpWebRequest
{
    private string _user;
    private string _password;
    private string _realm;
    private string _nonce;
    private string _qop;
    private string _cnonce;
    private string _opaque;
    private DateTime _cnonceDate;
    private int _nc;

    private string _requestMethod = WebRequestMethods.Http.Get;
    private string _contentType;
    private byte[] _postData;

    public DigestHttpWebRequest(string user, string password)
    {
        _user = user;
        _password = password;
    }

    public DigestHttpWebRequest(string user, string password, string realm)
    {
        _user = user;
        _password = password;
        _realm = realm;
    }

    public string Method
    {
        get { return _requestMethod; }
        set { _requestMethod = value; }
    }

    public string ContentType
    {
        get { return _contentType; }
        set { _contentType = value; }
    }

    public byte[] PostData
    {
        get { return _postData; }
        set { _postData = value; }
    }

    public HttpWebResponse GetResponse(Uri uri)
    {
        HttpWebResponse response = null;
        int infiniteLoopCounter = 0;
        int maxNumberAttempts = 2;

        while ((response == null ||
            response.StatusCode != HttpStatusCode.Accepted) &&
            infiniteLoopCounter < maxNumberAttempts)
        {
            try
            {
                var request = CreateHttpWebRequestObject(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", ComputeDigestHeader(uri));
                }

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

                        var wwwAuthenticateHeader = webException.Response.Headers["WWW-Authenticate"];
                        _realm = GetDigestHeaderAttribute("realm", wwwAuthenticateHeader);
                        _nonce = GetDigestHeaderAttribute("nonce", wwwAuthenticateHeader);
                        _qop = GetDigestHeaderAttribute("qop", wwwAuthenticateHeader);
                        _opaque = GetDigestHeaderAttribute("opaque", wwwAuthenticateHeader);

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

                        request = CreateHttpWebRequestObject(uri, true);

                        infiniteLoopCounter++;
                        response = (HttpWebResponse)request.GetResponse();
                    }
                    else
                    {
                        throw webException;
                    }
                }

                switch (response.StatusCode)
                {
                    case HttpStatusCode.OK:
                    case HttpStatusCode.Accepted:
                        return response;
                    case HttpStatusCode.Redirect:
                    case HttpStatusCode.Moved:
                        uri = new Uri(response.Headers["Location"]);

                        // We decrement the loop counter, as there might be a variable number of redirections which we should follow
                        infiniteLoopCounter--;
                        break;
                }

            }
            catch (WebException ex)
            {
                throw ex;
            }
        }

        throw new Exception("Error: Either authentication failed, authorization failed or the resource doesn't exist");
    }

    private HttpWebRequest CreateHttpWebRequestObject(Uri uri, bool addAuthenticationHeader)
    {
        var request = (HttpWebRequest)WebRequest.Create(uri);
        request.AllowAutoRedirect = true;
        request.PreAuthenticate = true;
        request.Method = this.Method;

        ///Only for test reason. The Ip is the one for fiddler
        //request.Proxy = new WebProxy("127.0.0.1:8888", true);

        if (!String.IsNullOrEmpty(this.ContentType))
        {
            request.ContentType = this.ContentType;
        }

        if (addAuthenticationHeader)
        {
            request.Headers.Add("Authorization", ComputeDigestHeader(uri));
        }

        if (this.PostData != null && this.PostData.Length > 0)
        {
            request.ContentLength = this.PostData.Length;
            Stream postDataStream = request.GetRequestStream(); //open connection
            postDataStream.Write(this.PostData, 0, this.PostData.Length); // Send the data.
            postDataStream.Close();
        }
        else if (
            this.Method == WebRequestMethods.Http.Post &&
            (this.PostData == null || this.PostData.Length == 0))
        {
            request.ContentLength = 0;
        }

        return request;
    }

    private HttpWebRequest CreateHttpWebRequestObject(Uri uri)
    {
        return CreateHttpWebRequestObject(uri, false);
    }

    private string ComputeDigestHeader(Uri uri)
    {
        _nc = _nc + 1;

        string ha1, ha2;

        ha1 = ComputeMd5Hash(string.Format("{0}:{1}:{2}", _user, _realm, _password));
        ha2 = ComputeMd5Hash(string.Format("{0}:{1}", this.Method, uri.PathAndQuery));
        var digestResponse =
            ComputeMd5Hash(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}\"," +
            "cnonce=\"{7}\",nc={6:00000000},qop={5},response=\"{4}\",opaque=\"{8}\"",
            _user, _realm, _nonce, uri.PathAndQuery, digestResponse, _qop, _nc, _cnonce, _opaque);

        throw new Exception("The digest header could not be generated");
    }

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

    private string ComputeMd5Hash(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 string WebServiceCall(string methodname)
    {
        try
        {
            string response = string.Empty;

            Uri uri = new Uri(string.Format("http://{0}:{1}/{2}", _servername, _port, methodname));

            DigestHttpWebRequest req = new DigestHttpWebRequest(_username, _password);

            using (HttpWebResponse webResponse = req.GetResponse(uri))
            using (Stream responseStream = webResponse.GetResponseStream())
            {
                if (responseStream != null)
                {
                    using (StreamReader streamReader = new StreamReader(responseStream))
                    {
                        response = streamReader.ReadToEnd();
                    }
                }
            }
            return response;
        }
        catch (WebException caught)
        {
            throw new WebException(string.Format("Exception in WebServiceCall: {0}", caught.Message));
        }
        catch (Exception caught)
        {
            throw new Exception(string.Format("Exception in WebServiceCall: {0}", caught.Message));
        }
    }

我希望這對某人有幫助,如果其他答案無效。

@christoph:謝謝您的幫助! 您與提琴手的小費幫助我找到了解決方案;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM