c# digest身份验证

Posted _iorilan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c# digest身份验证相关的知识,希望对你有一定的参考价值。

c# digest身份验证1. digest http request 类

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();
        



2. 发送digest请求

public class DigestProxy
    
        private static ILog _log = LogManager.GetLogger(typeof(DigestProxy));
        public static byte[] GetData(string url, string userName, string password)
        
            try
            
                Uri uri = new Uri(url);

                DigestHttpWebRequest req = new DigestHttpWebRequest(userName, password);

                using (HttpWebResponse webResponse = req.GetResponse(uri))
                using (Stream responseStream = webResponse.GetResponseStream())
                
                    using (var memoryStream = new MemoryStream())
                    
                        responseStream.CopyTo(memoryStream);
                        return memoryStream.ToArray();
                    
                
            
            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));
            
        

 

以上是关于c# digest身份验证的主要内容,如果未能解决你的问题,请参考以下文章

Android异常SASL身份验证失败使用机制DIGEST-MD5

如何让 MD5/digest 身份验证适用于不同的域? [关闭]

为啥来自其他用户的 Digest 身份验证 Java HttpClient 代码对我不起作用? [复制]

我可以使用 varnish 进行 HTTP Digest 身份验证吗

使用 Spring Security 在同一个 URI 映射上同时支持 Basic 和 Digest 身份验证

getInputStream 在 Android 的 Http Digest 身份验证期间给出 FileNotFoundException