使用 HttpWebRequest 瀏覽整合式 windows 認證環境的網站
一般來說,企業為了保密,或是避免員工亂來,
通常在公司電腦有做權限的管理,
常見的就是加入網域,走 Proxy 之類的作法,
員工電腦必須在網域下輸入帳號密碼才能進到 Windows。
上面講的跟主題有啥關係勒?
最近碰到的一個問題就出在這,
看下圖比較快:
因為某些需求,當使用者在瀏覽特定頁面的時候,例如頁面A;
會去觸發註冊在頁面A上的一個使用者控制項,(我比較喜歡稱為元件)
然後我們在控制項中加入 HttpWebRequest/Response,
讓程式「偷偷的」去瀏覽頁面B,
之所以會寫「偷偷的」,是因為控制項會去創造類似虛擬瀏覽器的環境,
去瀏覽並接受特定網址回傳的訊息,
由於這個動作是使用者不知情的(幕後執行),所以用「偷偷的」來形容。
網友看到這邊可能會有疑問…那為何頁面B要執行的程式不寫在頁面A就好?
還要如此大費周章?
這部分牽涉到頁面A重複使用性的問題,因為頁面A是同時給很多不同 Case 的使用者去瀏覽的,
而每個Case 要去觸發的狀況又不一樣,所以不能全寫死在程式中。
例如:使用者1瀏覽頁面A時,要幕後觸發的是頁面C,
使用者2瀏覽頁面A時,要幕後觸發的反而是頁面D。
寫完後,那程式應該可以 run 了吧?
但問題總出在令人意料不到的環節上:
沒錯,就是有問題!
就在我把頁面A打開的時候,出現了上圖的錯誤訊息,
關鍵就在 HttpWebRequest 所執行的身分以及授權。
其實當我們利用 Browser 瀏覽網站時,Browser 已經事先幫我們做了很多事情,
特別是在整合式 windows 認證環境的頁面,如果使用者是有登錄網域的,
則對使用者來說絲毫不會有任何差異,因為Browser 已經幫你完成認證了。
但是 HttpWebRequest 就不一樣了,它是程式創造出來的虛擬瀏覽器,
完全沒有任何權限,這將導致它在瀏覽一些非匿名存取的網站時,就會出現上面的錯誤。
先來看一下程式碼,標準 MSDN 的寫法:
02 {
03 try
04 {
05 string URL = "http://www.urWebName.com/"; //欲瀏覽的特定頁面
06
07 //初始化 HttpWebRequest
08 HttpWebRequest myHttpWebRequest = (HttpWebRequest)WebRequest.Create(URL);
09
10 // 設定內容類型
11 myHttpWebRequest.ContentType = "application/x-www-form-urlencoded";
12
13 //初始化 HttpWebResponse
14 HttpWebResponse myHttpWebResponse = (HttpWebResponse)myHttpWebRequest.GetResponse();
15 Stream msgstream = myHttpWebResponse.GetResponseStream(); //接收回傳訊息
16
17 Encoding encode = System.Text.Encoding.GetEncoding("utf-8"); //設定編碼方式
18
19 //用 StreamReader 讀出回傳訊息
20 StreamReader readStream = new StreamReader(msgstream, encode);
21
22 string Syslog = "";
23 Syslog = readStream.ReadToEnd();
24 readStream.Close();
25 }
26 catch (Exception e3)
27 {
28 Response.Write(e3.ToString());
29 }
30 }
爬了一下文之後,找到好幾種解決的方法,
例如將頁面設定為可匿名存取(可以過,但是一般不建議這樣的方式),
或是在 web.config 中加入:(試過還是不行)
最後找到的解法是在 GetResponse() 之前加上這一段:
這樣就可以用當時使用者當時登錄的身分進行認證,
另外,DefaultCredentials 只記錄了程式運作時的一些認證訊息,
而不會紀錄使用者的帳號和密碼,所以對安全性來說有一定幫助,
如果硬要檢視詳細的內容,也只會得到一堆空字串,
這或許也是微軟的保護機制吧!?
如果你要指定一個身分去登錄網站的話,可以這樣做:
2 NetworkCredential netCreden=new NetworkCredential("userName", "userPW"); //登入的帳號密碼
3 myHttpWebRequest.Credentials = netCreden.GetCredential(new Uri(URL), "authType"); //要瀏覽的網址以及認證類型
4
當然,如果你的認證方式是預設值且網址URL跟最前面相同的話,
最後一行可以簡寫為