2011-10-22 46 views
0

我正在努力開發一個C#類來登錄到Web主機(Hostgator)上的cPanel。無法用C#WebRequest登錄到cPanel

在PHP這是很容易使用curl擴展如下:

$url = "http://mysite.com:2082/"; 

$c = curl_init($url); 

curl_setopt($c, CURLOPT_USERPWD, 'user:password'); 
curl_setopt($c, CURLOPT_RETURNTRANSFER, 1); 
$result = curl_exec($c); 
if ($result === false) 
    $result = curl_error($c); 
curl_close($c); 

file_put_contents('log.txt', $result); 
//print_r($result); 

現在,這裏是我的C#類的各種嘗試,使其工作註釋掉:

class HTTPHandler 
{ 
    public static string Connect (string url, string userName, string password) 
    { 
     string result; 

     try 
     { 
      // An initial @ symbol in the password must be escaped 
      if (password.Length > 0) 
       if (password[0] == '@') 
        password = "\\" + password; 

      // Create a request for the URL.   
      WebRequest request = WebRequest.Create(url); 
      request.PreAuthenticate = true; 
      request.Credentials = new NetworkCredential(userName, password); 

      /* 
      var credCache = new CredentialCache(); 
      credCache.Add(new Uri(url), "Basic", 
           new NetworkCredential(userName, password)); 
      request.Credentials = credCache; 
      */ 

      //request.Method = "POST"; 
      //request.ContentType = "application/x-www-form-urlencoded"; 

      /* 
      // Create POST data and convert it to a byte array. 
      string postData = string.Format("user={0}&pass={1}", userName, password); 
      byte[] byteArray = Encoding.UTF8.GetBytes(postData); 
      request.ContentLength = byteArray.Length; 
      request.ContentType = "application/x-www-form-urlencoded"; 
      Stream dataStream = request.GetRequestStream(); 
      dataStream.Write(byteArray, 0, byteArray.Length); 
      dataStream.Close(); 
      */ 

      // Get the response. 
      HttpWebResponse response = (HttpWebResponse)request.GetResponse(); 

      // Get the stream containing content returned by the server. 
      Stream dataStream = response.GetResponseStream(); 
      // Open the stream using a StreamReader for easy access. 
      StreamReader reader = new StreamReader(dataStream); 
      // Display the content. 
      result = string.Format("Server response:\n{0}\n{1}", response.StatusDescription, reader.ReadToEnd()); 
      // Cleanup the streams and the response. 
      reader.Close(); 
      dataStream.Close(); 
      response.Close(); 
     } 
     catch (Exception e) 
     { 
      result = string.Format("There was an error:\n{0}", e.Message); 
     } 

     return result; 
    } 
} 

}

但我一直在GetResponse階段收到錯誤401(未授權)。

當我比較我的本地主機測試頁中的PHP和C#提交之間的$ _SERVER變量時,除了發送端口有點不同之外,我獲得了相同的數據。關鍵的PHP_AUTH_USER和PHP_AUTH_PW是相同的。

我的操作系統是Windows 7 64位和我使用的Visual C#2010

我猜的解決方案是非常簡單的,但到目前爲止,我感到莫名其妙。但是C#的相對新手。我希望有人能幫忙。

回答

1

你並不需要設置PreAuthenticate,只是讓請求找出來。另外我會建議使用HttpWebRequest而不是WebRequest。主要區別在於您可以設置CookieContainer屬性來啓用Cookie。這有點令人困惑,因爲默認情況下它會禁用Cookie,您只需將其設置爲new CookieContainer();即可爲您的請求啓用Cookie。 這很重要,因爲在身份驗證過程中發生了重定向,並且auth cookie記錄了您成功通過身份驗證的事實。

另外還有一種編碼風格的註釋:請確保在using()聲明中包含所有IDisposable(如響應,流和閱讀器)。

另外我不清楚你爲什麼要在密碼中轉義@。請求應該自動處理所有的編碼需求。

完整的示例代碼:

var request = WebRequest.CreateHttp(url); 
request.Credentials = new NetworkCredential(username, password); 
request.CookieContainer = new CookieContainer(); // needed to enable cookies 

using (var response = (HttpWebResponse)request.GetResponse()) 
using (var reader = new StreamReader(response.GetResponseStream(), Encoding.GetEncoding(response.CharacterSet))) 
    return string.Format("Server response:\n{0}\n{1}", response.StatusDescription, reader.ReadToEnd()); 

編輯:對不起,所有的編輯。我正在用內存編寫代碼,並且正在努力使編碼部分正確。

+0

謝謝您的回答。使用本地服務器上的測試頁面,我沒有使用PreAuthenticate接收用戶名和密碼的詳細信息到PHP頁面。和Curl一起,我不需要使用cookies。我發現在使用PHP和Curl連接到cPanel之前,我不得不跳過最初的@字符。 – Andy

+0

@好的,但你有嘗試過嗎? –

+0

希望有Linux主機與cPanel的人可以測試一些成功登錄的C#代碼。它與Cookie無關,因爲您必須使其通過GetResponse階段而沒有錯誤。只需模擬我的PHP示例。 – Andy

1

這是使用System.Web,我必須將項目屬性設置爲使用完整的.NET Framework 4才能訪問HttpUtility的此程序集並在參考中添加對System.Web的引用。

我沒有測試所有的重載方法,但主要的是cPanel連接,當userName存在時,身份驗證憑證被添加到http頭中。

此外,對於cPanel我需要設置request.AllowAutoRedirect = false;所以我控制逐頁訪問,因爲我沒有設法捕獲cookie。

下面是HTTP助手類,我想出了代碼:

class HTTPHandler 
{ 
    // Some default settings 
    const string UserAgent = "Bot"; // Change this to something more meaningful 
    const int TimeOut = 1000; // Time out in ms 

    // Basic connection 
    public static string Connect(string url) 
    { 
     return Connect(url, "", "", UserAgent, "", TimeOut); 
    } 

    // Connect with post data passed as a key : value pair dictionary 
    public static string Connect(string url, Dictionary<string, string> args) 
    { 
     return Connect(url, "", "", UserAgent, ToQueryString(args), TimeOut); 
    } 

    // Connect with a custom user agent specified 
    public static string Connect(string url, string userAgent) 
    { 
     return Connect(url, "", "", userAgent, "", TimeOut); 
    } 

    public static string Connect(string url, string userName, string password, string userAgent, string postData, int timeOut) 
    { 
     string result; 

     try 
     { 
      // Create a request for the URL.   
      HttpWebRequest request = (HttpWebRequest)WebRequest.Create(url); 

      if (userAgent == null) 
       userAgent = UserAgent; 

      request.UserAgent = userAgent; 
      request.Timeout = timeOut; 

      if (userName.Length > 0) 
      { 
       string authInfo = userName + ":" + password; 
       authInfo = Convert.ToBase64String(Encoding.Default.GetBytes(authInfo)); 
       request.Headers["Authorization"] = "Basic " + authInfo; 
       request.AllowAutoRedirect = false; 
      } 

      if (postData.Length > 0) 
      { 
       request.Method = "POST"; 
       request.ContentType = "application/x-www-form-urlencoded"; 

       // Create POST data and convert it to a byte array. 
       byte[] byteArray = Encoding.UTF8.GetBytes(postData); 
       request.ContentLength = byteArray.Length; 
       using (Stream dataStream = request.GetRequestStream()) 
       { 
        dataStream.Write(byteArray, 0, byteArray.Length); 
       } 
      } 

      // Get the response. 
      using (HttpWebResponse response = (HttpWebResponse)request.GetResponse()) 
      { 
       // Get the stream containing content returned by the server. 
       Stream dataStream = response.GetResponseStream(); 
       // Open the stream using a StreamReader for easy access. 
       using (StreamReader reader = new StreamReader(dataStream)) 
       { 
        result = string.Format("Server response:\n{0}\n{1}", response.StatusDescription, reader.ReadToEnd()); 
       } 
      } 
     } 

     catch (Exception e) 
     { 
      result = string.Format("There was an error:\n{0}", e.Message); 
     } 

     return result; 
    } 

    public static string ToQueryString(Dictionary<string, string> args) 
    { 
     List<string> encodedData = new List<string>(); 

     foreach (KeyValuePair<string, string> pair in args) 
     { 
      encodedData.Add(HttpUtility.UrlEncode(pair.Key) + "=" + HttpUtility.UrlEncode(pair.Value)); 
     } 

     return String.Join("&", encodedData.ToArray()); 
    } 
}