2013-04-16 24 views
43

Chỉnh sửa: Tôi muốn quay lại để lưu ý rằng vấn đề không phải là kết thúc của tôi chút nào, mà là với mã ở phía bên kia của công ty.Webclient/HttpWebRequest với xác thực cơ bản trả về 404 không được tìm thấy cho URL hợp lệ

Tôi đang cố gắng để kéo lên một trang bằng cách sử dụng Xác thực cơ bản. Tôi tiếp tục gặp lỗi 404 Trang không tìm thấy. Tôi có thể sao chép và dán url của tôi vào trình duyệt và nó hoạt động tốt (nếu tôi không đăng nhập vào trang web của họ đã được nó bật lên một hộp thông tin xác thực, nếu không nó sẽ mở ra những gì tôi muốn nó mở). Tôi phải đến đúng nơi và xác thực, bởi vì tôi nhận được lỗi 401 (không được xác thực) nếu tôi đặt tên người dùng/mật khẩu sai và tôi gặp lỗi máy chủ nội bộ 500 nếu tôi chuyển thông số xấu trong chuỗi truy vấn . Tôi đã thử sử dụng Webclient và HttpWebRequest cả hai dẫn đến cùng một lỗi 404 không tìm thấy.

Với WebClient:

 string url = "MyValidURLwithQueryString"; 
     WebClient client = new WebClient(); 
     String userName = "myusername"; 
     String passWord = "mypassword"; 
     string credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(userName + ":" + passWord)); 
     client.Headers[HttpRequestHeader.Authorization] = "Basic " + credentials; 
     var result = client.DownloadString(url); 
     Response.Write(result); 

Với HttpWebRequest

 HttpWebRequest request = (HttpWebRequest)WebRequest.Create("MyValidURL"); 
     string authInfo = "username:password"; 
     authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); 
     request.Headers.Add("Authorization", "Basic " + authInfo); 
     request.Credentials = new NetworkCredential("username", "password"); 
     request.Method = WebRequestMethods.Http.Get; 
     request.AllowAutoRedirect = true; 
     request.Proxy = null; 
     HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 
     Stream stream = response.GetResponseStream(); 
     StreamReader streamreader = new StreamReader(stream); 
     string s = streamreader.ReadToEnd(); 
     Response.Write(s); 
+1

Sử dụng [Fiddler] (http://fiddler2.com/), đăng nhập vào trang web của bạn thông qua trình duyệt và xem tiêu đề/nội dung trình duyệt của bạn gửi. Đoán của tôi, bạn cũng nên đặt 'UserAgent' – I4V

+0

Thông tin tiêu đề là chính xác tìm kiếm trong fiddler và tôi cũng đã cố gắng thiết lập UserAgent tại một thời điểm từ một bài trước tôi đã xem xét rằng đề nghị cùng một điều. –

+0

404 không đến từ WebClient - nó từ máy chủ. Có điều gì đó mà máy chủ không thích từ chương trình của bạn, mà nó thích từ trình duyệt. Sử dụng Fiddler để làm cho giao diện WebClient của bạn trông giống như trình duyệt. –

Trả lời

20

Hãy thử thay đổi Web Client phần yêu cầu xác thực để:

NetworkCredential myCreds = new NetworkCredential(userName, passWord); 
client.Credentials = myCreds; 

Sau đó, thực hiện cuộc gọi của bạn, dường như làm việc tốt cho tôi.

+0

Tôi đã thử đặt thuộc tính thông tin xác thực là tốt và nó cho cùng một vấn đề. –

+0

Nó làm việc cho tôi. – matrix

58
//BEWARE 
//This works ONLY if the server returns 401 first 
//The client DOES NOT send credentials on first request 
//ONLY after a 401 
client.Credentials = new NetworkCredential(userName, passWord); //doesnt work 

//So use THIS instead to send credentials RIGHT AWAY 
string credentials = Convert.ToBase64String(
    Encoding.ASCII.GetBytes(userName + ":" + password)); 
client.Headers[HttpRequestHeader.Authorization] = string.Format(
    "Basic {0}", credentials); 
+0

Wow! lưu ý quan trọng có liên quan đến phương pháp được mô tả bởi @Blake không hoạt động cho đến khi yêu cầu thứ hai. Kudos cho giải pháp – Korayem

+0

Tôi đã đấu tranh với một vấn đề tương tự và điều này hoàn toàn cố định nó. CẢM ƠN BẠN! – onekidney

+0

vẫn nhận được 404 – Dmitry

7

phần mã này làm việc tốt cho tôi:

 WebRequest request = WebRequest.Create(url); 
     request.Method = WebRequestMethods.Http.Get; 
     NetworkCredential networkCredential = new NetworkCredential(logon, password); // logon in format "domain\username" 
     CredentialCache myCredentialCache = new CredentialCache {{new Uri(url), "Basic", networkCredential}}; 
     request.PreAuthenticate = true; 
     request.Credentials = myCredentialCache; 
     using (WebResponse response = request.GetResponse()) 
     { 
      Console.WriteLine(((HttpWebResponse)response).StatusDescription); 

      using (Stream dataStream = response.GetResponseStream()) 
      { 
       using (StreamReader reader = new StreamReader(dataStream)) 
       { 
        string responseFromServer = reader.ReadToEnd(); 
        Console.WriteLine(responseFromServer); 
       } 
      } 
     } 
2

Nếu làm việc của nó khi bạn đang sử dụng một trình duyệt và sau đó đi qua vào tên người dùng và mật khẩu cho lần đầu tiên - sau đó điều này có nghĩa rằng một khi xác thực được thực hiện Yêu cầu tiêu đề của trình duyệt của bạn được thiết lập với các giá trị xác thực yêu cầu, sau đó được truyền vào mỗi lần yêu cầu được thực hiện cho máy chủ lưu trữ.

Vì vậy, bắt đầu với việc kiểm tra tiêu đề yêu cầu (điều này có thể được thực hiện bằng cách sử dụng công cụ nhà phát triển web), một khi bạn thiết lập những gì cần thiết trong tiêu đề thì bạn có thể vượt qua điều này trong tiêu đề HttpWebRequest của bạn.

Ví dụ với Digest Authentication:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Security.Cryptography; 
using System.Text.RegularExpressions; 
using System.Net; 
using System.IO; 

namespace NUI 
{ 
    public class DigestAuthFixer 
    { 
     private static string _host; 
     private static string _user; 
     private static string _password; 
     private static string _realm; 
     private static string _nonce; 
     private static string _qop; 
     private static string _cnonce; 
     private static DateTime _cnonceDate; 
     private static int _nc; 

public DigestAuthFixer(string host, string user, string password) 
{ 
    // TODO: Complete member initialization 
    _host = host; 
    _user = user; 
    _password = password; 
} 

private 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 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)); 
} 

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

}

Sau đó, bạn có thể gọi nó là:

DigestAuthFixer digest = new DigestAuthFixer(domain, username, password); 
string strReturn = digest.GrabResponse(dir); 

nếu Url là: http://xyz.rss.com/folder/rss thì tên miền: http://xyz.rss.com (phần tên miền) dir:/thư mục/rss (phần còn lại của url)

bạn cũng có thể trả về nó dưới dạng luồng và sử dụng phương thức Load() của XmlDocument.

Các vấn đề liên quan