上篇博客我談到了一些關於ASP.NET Forms身份認證方面的話題,此次的博客將主要介紹ASP.NET Windows身份認證。web
Forms身份認證雖然使用普遍,不過,若是是在 Windows Active Directory 的環境中使用ASP.NET, 那麼使用Windows身份認證也會比較方便。 方便性表現爲:咱們不用再設計登陸頁面,不用編寫登陸驗證邏輯。並且使用Windows身份認證會有更好的安全保障。編程
要使用Windows身份認證模式,須要在web.config設置:瀏覽器
<authentication mode="Windows" />
Windows身份認證作爲ASP.NET的默認認證方式,與Forms身份認證在許多基礎方面是同樣的。 上篇博客我說過:我認爲ASP.NET的身份認證的最核心部分其實就是HttpContext.User這個屬性所指向的對象。 在接下來的部分,我將着重分析這個對象在二種身份認證中有什麼差異。緩存
在ASP.NET身份認證過程當中,IPrincipal和IIdentity這二個接口有着很是重要的做用。 前者定義用戶對象的基本功能,後者定義標識對象的基本功能, 不一樣的身份認證方式獲得的這二個接口的實例也是不一樣的。安全
ASP.NET Windows身份認證是由WindowsAuthenticationModule實現的。 WindowsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中, 使用從IIS傳遞到ASP.NET的Windows訪問令牌(Token)建立一個WindowsIdentity對象,Token經過調用context.WorkerRequest.GetUserToken()得到, 而後再根據WindowsIdentity 對象建立WindowsPrincipal對象, 而後把它賦值給HttpContext.User。服務器
在Forms身份認證中,咱們須要建立登陸頁面,讓用戶提交用戶名和密碼,而後檢查用戶名和密碼的正確性, 接下來建立一個包含FormsAuthenticationTicket對象的登陸Cookie供後續請求使用。 FormsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中, 解析登陸Cookie並建立一個包含FormsIdentity的GenericPrincipal對象, 而後把它賦值給HttpContext.User。網絡
上面二段話簡單了歸納了二種身份認證方式的工做方式。 咱們能夠發現它們存在如下差異: 1. Forms身份認證須要Cookie表示登陸狀態,Windows身份認證則依賴於IIS 2. Windows身份認證不須要咱們設計登陸頁面,不用編寫登陸驗證邏輯,所以更容易使用。dom
在受權階段,UrlAuthorizationModule仍然會根據當前用戶檢查將要訪問的資源是否獲得許可。 接下來,FileAuthorizationModule檢查 HttpContext.User.Identity 屬性中的 IIdentity 對象是不是 WindowsIdentity 類的一個實例。 若是 IIdentity 對象不是 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類中止處理。 若是存在 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類調用 AccessCheck Win32 函數(經過 P/Invoke) 來肯定是否受權通過身份驗證的客戶端訪問請求的文件。 若是該文件的安全描述符的隨機訪問控制列表 (DACL) 中至少包含一個 Read 訪問控制項 (ACE),則容許該請求繼續。 不然,FileAuthorizationModule 類調用 HttpApplication.CompleteRequest 方法並將狀態碼 401 返回到客戶端。 ide
在Windows身份認證中,驗證工做主要是由IIS實現的,WindowsAuthenticationModule其實只是負責建立WindowsPrincipal和WindowsIdentity而已。 順便介紹一下:Windows 身份驗證又分爲「NTLM 身份驗證」和「Kerberos v5 身份驗證」二種, 關於這二種Windows身份認證的更多說明可查看MSDN技術文章:解釋:ASP.NET 2.0 中的 Windows 身份驗證。 在我看來,IIS最終使用哪一種Windows身份認證方式並不影響咱們的開發過程,所以本文不會討論這個話題。
根據個人實際經驗來看,使用Windows身份認證時,主要的開發工做將是根據登陸名從Active Directory獲取用戶信息。 由於,此時不須要咱們再設計登陸過程,IIS與ASP.NET已經爲咱們準備好了WindowsPrincipal和WindowsIdentity這二個與用戶身份相關的對象。
咱們一般使用LDAP協議來訪問Active Directory, 在.net framework中提供了DirectoryEntry和DirectorySearcher這二個類型讓咱們能夠方便地從託管代碼中訪問 Active Directory 域服務。
若是咱們要在"test.corp」這個域中搜索某個用戶信息,咱們可使用下面的語句構造一個DirectoryEntry對象:
DirectoryEntry entry = new DirectoryEntry("LDAP://test.corp");
在這段代碼中,我採用硬編碼的方式把域名寫進了代碼。 咱們如何知道當前電腦所使用的是哪一個域名呢? 答案是:查看「個人電腦」的屬性對話框:
注意:這個域名不必定與System.Environment.UserDomainName相同。
除了能夠查看「個人電腦」的屬性對話框外,咱們還可使用代碼的方式獲取當前電腦所使用的域名:
private static string GetDomainName()
{
// 注意:這段代碼須要在Windows XP及較新版本的操做系統中才能正常運行。 SelectQuery query = new SelectQuery("Win32_ComputerSystem"); using( ManagementObjectSearcher searcher = new ManagementObjectSearcher(query) ) { foreach( ManagementObject mo in searcher.Get() ) { if( (bool)mo["partofdomain"] ) return mo["domain"].ToString(); } } return null; }
當構造了DirectorySearcher對象後,咱們即可以使用DirectorySearcher來執行對Active Directory的搜索。 咱們可使用下面的步驟來執行搜索: 1. 設置 DirectorySearcher.Filter 指示LDAP格式篩選器,這是一個字符串。 2. 屢次調用PropertiesToLoad.Add() 設置搜索過程當中要檢索的屬性列表。 3. 調用FindOne() 方法獲取搜索結果。
下面的代碼演示瞭如何從Active Directory中搜索登陸名爲「fl45」的用戶信息:
static void Main(string[] args) { Console.WriteLine(Environment.UserDomainName); Console.WriteLine(Environment.UserName); Console.WriteLine("------------------------------------------------"); ShowUserInfo("fl45", GetDomainName()); } private static string AllProperties = "name,givenName,samaccountname,mail"; public static void ShowUserInfo(string loginName, string domainName) { if( string.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(domainName) ) return; string[] properties = AllProperties.Split(new char[] { '\r', '\n', ',' }, StringSplitOptions.RemoveEmptyEntries); try { DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName); DirectorySearcher search = new DirectorySearcher(entry); search.Filter = "(samaccountname=" + loginName + ")"; foreach( string p in properties ) search.PropertiesToLoad.Add(p); SearchResult result = search.FindOne(); if( result != null ) { foreach( string p in properties ) { ResultPropertyValueCollection collection = result.Properties[p]; for( int i = 0; i < collection.Count; i++ ) Console.WriteLine(p + ": " + collection[i]); } } } catch( Exception ex ) { Console.WriteLine(ex.ToString()); } }
結果以下:
在前面的代碼,我在搜索Active Directory時,只搜索了"name,givenName,samaccountname,mail"這4個屬性。 然而,LDAP還支持更多的屬性,咱們可使用下面的代碼查看更多的用戶信息:
private static string AllProperties = @" homemdb distinguishedname countrycode cn lastlogoff mailnickname dscorepropagationdata msexchhomeservername msexchmailboxsecuritydescriptor msexchalobjectversion usncreated objectguid whenchanged memberof msexchuseraccountcontrol accountexpires displayname primarygroupid badpwdcount objectclass instancetype objectcategory samaccounttype whencreated lastlogon useraccountcontrol physicaldeliveryofficename samaccountname usercertificate givenname mail userparameters adspath homemta msexchmailboxguid pwdlastset logoncount codepage name usnchanged legacyexchangedn proxyaddresses department userprincipalname badpasswordtime objectsid sn mdbusedefaults telephonenumber showinaddressbook msexchpoliciesincluded textencodedoraddress lastlogontimestamp company ";
前面我在一個控制檯程序中演示了訪問Active Directory的方法,經過示例咱們能夠看到:在代碼中,我用Environment.UserName就能夠獲得當前用戶的登陸名。 然而,若是是在ASP.NET程序中,訪問Environment.UserName就頗有可能得不到真正用戶登陸名。 由於:Environment.UserName是使用WIN32API中的GetUserName獲取線程相關的用戶名,但ASP.NET運行在IIS中,線程相關的用戶名就不必定是客戶端的用戶名了。 不過,ASP.NET能夠模擬用戶方式運行,經過這種方式才能夠獲得正確的結果。關於「模擬」的話題在本文的後面部分有說明。
在ASP.NET中,爲了能可靠的獲取登陸用戶的登陸名,咱們可使用下面的代碼:
/// <summary>
/// 根據指定的HttpContext對象,獲取登陸名。 /// </summary> /// <param name="context"></param> /// <returns></returns> public static string GetUserLoginName(HttpContext context) { if( context == null ) return null; if( context.Request.IsAuthenticated == false ) return null; string userName = context.User.Identity.Name; // 此時userName的格式爲:UserDomainName\LoginName // 咱們只須要後面的LoginName就能夠了。 string[] array = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); if( array.Length == 2 ) return array[1]; return null; }
在ASP.NET中使用Windows身份認證時,IIS和WindowsAuthenticationModule已經作了許多驗證用戶的相關工做, 雖然咱們可使用前面的代碼獲取到用戶的登陸名,但用戶的其它信息即須要咱們本身來獲取。 在實際使用Windows身份認證時,咱們要作的事:基本上就是從Active Directory中根據用戶的登陸名獲取所需的各類信息。
好比:個人程序在運行時,還須要使用如下與用戶相關的信息:
public sealed class UserInfo { public string GivenName; public string FullName; public string Email; }
public static class UserHelper { /// <summary> /// 活動目錄中的搜索路徑,也可根據實際狀況來修改這個值。 /// </summary> public static string DirectoryPath = "LDAP://" + GetDomainName(); /// <summary> /// 獲取與指定HttpContext相關的用戶信息 /// </summary> /// <param name="context"></param> /// <returns></returns> public static UserInfo GetCurrentUserInfo(HttpContext context) { string loginName = GetUserLoginName(context); if( string.IsNullOrEmpty(loginName) ) return null; return GetUserInfoByLoginName(loginName); } /// <summary> /// 根據指定的HttpContext對象,獲取登陸名。 /// </summary> /// <param name="context"></param> /// <returns></returns> public static string GetUserLoginName(HttpContext context) { if( context == null ) return null; if( context.Request.IsAuthenticated == false ) return null; string userName = context.User.Identity.Name; // 此時userName的格式爲:UserDomainName\LoginName // 咱們只須要後面的LoginName就能夠了。 string[] array = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries); if( array.Length == 2 ) return array[1]; return null; } /// <summary> /// 根據登陸名查詢活動目錄,獲取用戶信息。 /// </summary> /// <param name="loginName"></param> /// <returns></returns> public static UserInfo GetUserInfoByLoginName(string loginName) { if( string.IsNullOrEmpty(loginName) ) return null; // 下面的代碼將根據登陸名查詢用戶在AD中的信息。 // 爲了提升性能,能夠在此處增長一個緩存容器(Dictionary or Hashtable)。 try { DirectoryEntry entry = new DirectoryEntry(DirectoryPath); DirectorySearcher search = new DirectorySearcher(entry); search.Filter = "(SAMAccountName=" + loginName + ")"; search.PropertiesToLoad.Add("givenName"); search.PropertiesToLoad.Add("cn"); search.PropertiesToLoad.Add("mail"); // 若是還須要從AD中獲取其它的用戶信息,請參考ActiveDirectoryDEMO SearchResult result = search.FindOne(); if( result != null ) { UserInfo info = new UserInfo(); info.GivenName = result.Properties["givenName"][0].ToString(); info.FullName = result.Properties["cn"][0].ToString(); info.Email = result.Properties["mail"][0].ToString(); return info; } } catch { // 若是須要記錄異常,請在此處添加代碼。 } return null; } private static string GetDomainName() { // 注意:這段代碼須要在Windows XP及較新版本的操做系統中才能正常運行。 SelectQuery query = new SelectQuery("Win32_ComputerSystem"); using( ManagementObjectSearcher searcher = new ManagementObjectSearcher(query) ) { foreach( ManagementObject mo in searcher.Get() ) { if( (bool)mo["partofdomain"] ) return mo["domain"].ToString(); } } return null; } }
使用UserHelper的頁面代碼:
<html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>WindowsAuthentication DEMO - http://www.cnblogs.com/fish-li/</title> </head> <body> <% if( Request.IsAuthenticated ) { %> 當前登陸全名:<%= Context.User.Identity.Name.HtmlEncode()%> <br /> <% var user = UserHelper.GetCurrentUserInfo(Context); %> <% if( user != null ) { %> 用戶短名:<%= user.GivenName.HtmlEncode()%> <br /> 用戶全名:<%= user.FullName.HtmlEncode() %> <br /> 郵箱地址:<%= user.Email.HtmlEncode() %> <% } %> <% } else { %> 當前用戶還未登陸。 <% } %> </body> </html>
程序運行的效果以下:
另外,還能夠從Active Directory查詢一個叫作memberof的屬性(它與Windows用戶組無關),有時候能夠用它區分用戶,設計與權限相關的操做。
在設計數據持久化的表結構時,因爲此時沒有「用戶表」,那麼咱們能夠直接保存用戶的登陸名。 剩下的開發工做就與Forms身份認證沒有太多的差異了。
前面介紹了ASP.NET Windows身份認證,在這種方式下,IIS和WindowsAuthenticationModule爲咱們實現了用戶身份認證的過程。 然而,有時可能因爲各類緣由,須要咱們以編程的方式使用Active Directory驗證用戶身份,好比:在WinForm程序,或者其它的驗證邏輯。
咱們不只能夠從Active Directory中查詢用戶信息,也能夠用它來實現驗證用戶身份,這樣即可以實現本身的登陸驗證邏輯。
無論是如何使用Active Directory,咱們都須要使用DirectoryEntry和DirectorySearcher這二個對象。 DirectoryEntry還提供一個構造函數可以讓咱們輸入用戶名和密碼:
// 摘要:
// 初始化 System.DirectoryServices.DirectoryEntry 類的新實例。
//
// 參數:
// Password:
// 在對客戶端進行身份驗證時使用的密碼。DirectoryEntry.Password 屬性初始化爲該值。
//
// username:
// 在對客戶端進行身份驗證時使用的用戶名。DirectoryEntry.Username 屬性初始化爲該值。
//
// Path:
// 此 DirectoryEntry 的路徑。DirectoryEntry.Path 屬性初始化爲該值。
public DirectoryEntry(string path, string username, string password);
要實現本身的登陸檢查,就須要使用這個構造函數。 如下是我寫用WinForm寫的一個登陸檢查的示例:
private void btnLogin_Click(object sender, EventArgs e) { if( txtUsername.Text.Length == 0 || txtPassword.Text.Length == 0 ) { MessageBox.Show("用戶名或者密碼不能爲空。", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning); return; } string ldapPath = "LDAP://" + GetDomainName(); string domainAndUsername = Environment.UserDomainName + "\\" + txtUsername.Text; DirectoryEntry entry = new DirectoryEntry(ldapPath, domainAndUsername, txtPassword.Text); DirectorySearcher search = new DirectorySearcher(entry); try { SearchResult result = search.FindOne(); MessageBox.Show("登陸成功。", this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information); } catch( Exception ex ) { // 若是用戶名或者密碼不正確,也會拋出異常。 MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop); } }
程序運行的效果以下:
在ASP.NET Windows身份認證環境中,與用戶相關的安全上下文對象保存在HttpContext.User屬性中,是一個類型爲WindowsPrincipal的對象, 咱們還能夠訪問HttpContext.User.Identity來獲取通過身份認證的用戶標識,它是一個WindowsIdentity類型的對象。
在.NET Framework中,咱們能夠經過WindowsIdentity.GetCurrent()獲取與當前線程相關的WindowsIdentity對象, 這種方法獲取的是當前運行的Win32線程的安全上下文標識。 因爲ASP.NET運行在IIS進程中,所以ASP.NET線程的安全標識實際上是從IIS的進程中繼承的, 因此此時用二種方法獲得的WindowsIdentity對象實際上是不一樣的。
在Windows操做系統中,許多權限檢查都是基於Win32線程的安全上下文標識, 因而前面所說的二種WindowsIdentity對象會形成編程模型的不一致問題, 爲了解決這個問題,ASP.NET提供了「模擬」功能,容許線程以特定的Windows賬戶的安全上下文來訪問資源。
爲了能更好的理解模擬的功能,我準備了一個示例(ShowWindowsIdentity.ashx):
public class ShowWindowsIdentity : IHttpHandler { public void ProcessRequest (HttpContext context) { // 要觀察【模擬】的影響, // 能夠啓用,禁止web.config中的設置:<identity impersonate="true"/> context.Response.ContentType = "text/plain"; context.Response.Write(Environment.UserDomainName + "\\" + Environment.UserName + "\r\n"); WindowsPrincipal winPrincipal = (WindowsPrincipal)HttpContext.Current.User; context.Response.Write(string.Format("HttpContext.Current.User.Identity: {0}, {1}\r\n", winPrincipal.Identity.AuthenticationType, winPrincipal.Identity.Name)); WindowsPrincipal winPrincipal2 = (WindowsPrincipal)Thread.CurrentPrincipal; context.Response.Write(string.Format("Thread.CurrentPrincipal.Identity: {0}, {1}\r\n", winPrincipal2.Identity.AuthenticationType, winPrincipal2.Identity.Name)); WindowsIdentity winId = WindowsIdentity.GetCurrent(); context.Response.Write(string.Format("WindowsIdentity.GetCurrent(): {0}, {1}", winId.AuthenticationType, winId.Name)); }
首先,在web.config中設置:
<authentication mode="Windows" />
注意:要把網站部署在IIS中,不然看不出效果。
此時,訪問ShowWindowsIdentity.ashx,將看到以下圖所示的結果:
如今修改一下web.config中設置:(注意:後面加了一句配置)
<authentication mode="Windows" /> <identity impersonate="true"/>
此時,訪問ShowWindowsIdentity.ashx,將看到以下圖所示的結果:
說明: 1. FISH-SRV2003是個人計算機名。它在一個沒有域的環境中。 2. fish-li是個人一個Windows賬號的登陸名。 3. 網站部署在IIS6中,進程以NETWORK SERVICE賬號運行。 4. 打開網頁時,我輸入的用戶名是fish-li
前面二張圖片的差別之處其實也就是ASP.NET的「模擬」所發揮的功能。
關於模擬,我想說四點: 1. 在ASP.NET中,咱們應該訪問HttpContext.User.Identity獲取當前用戶標識,那麼就不存在問題(此時能夠不須要模擬),例如FileAuthorizationModule就是這樣處理的。 2. 模擬只是在ASP.NET應用程序訪問Windows系統資源時須要應用Windows的安全檢查功能纔會有用。 3. Forms身份認證也能配置模擬功能,但只能模擬一個Windows賬戶。 4. 絕大多數狀況下是不須要模擬的。
與使用Forms身份認證的程序不一樣,使用Windows身份認證的程序須要額外的配置步驟。 這個小節將主要介紹在IIS中配置Windows身份認證,我將經常使用的IIS6和IIS7.5爲例分別介紹這些配置。
IIS6的配置 請參考下圖:
IIS7.5的配置 請參考下圖:
注意:Windows身份認證是須要安裝的,方法請參考下圖:
當咱們用瀏覽器訪問一個使用Windows身份認證的網站時,瀏覽器都會彈出一個對話框(左IE,右Safari):
此時,要求咱們輸入Windows的登陸賬號,而後交給IIS驗證身份。
首次彈出這個對話框很正常:由於程序要驗證用戶的身份。 然而,每次關閉瀏覽器下次從新打開頁面時,又會出現此對話框,此時感受就很不方便了。 雖然有些瀏覽器能記住用戶名和密碼,但我發現FireFox,Opera,Chrome仍然會彈出這個對話框,等待咱們點擊肯定, 只有Safari纔不會打擾用戶直接打開網頁。 IE的那個「記住個人密碼」複選框徹底是個擺設,它根本不會記住密碼!
所以,我所試過的全部瀏覽器中,只有Safari是最人性化的。 雖然在默認狀況下,雖然IE不會記住密碼,每次都須要再次輸入。 不過,IE卻能夠支持不提示用戶輸入登陸賬號而直接打開網頁, 此時IE將使用用戶的當前Windows登陸賬號傳遞給IIS驗證身份。
要讓IE打開一個Windows身份認證的網站不提示登陸對話框,必須知足如下條件: 1. 必須在 IIS 的 Web 站點屬性中啓用 Windows 集成身份驗證。 2. 客戶端和Web服務器都必須在基於Microsoft Windows的同一個域內。 3. Internet Explorer 必須把所請求的 URL 視爲 Intranet(本地)。 4. Internet Explorer 的 Intranet 區域的安全性設置必須設爲「只在 Intranet 區域自動登陸」。 5. 請求Web頁的用戶必須具備訪問該Web頁以及該Web頁中引用的全部對象的適當的文件系統(NTFS)權限。 6. 用戶必須用域賬號登陸到Windows 。
在這幾個條件中,若是網站是在一個Windows域中運行,除了第3條可能不知足外,其它條件應該都容易知足(第4條是默認值)。 所以,要讓IE不提示輸入登陸賬號,只要確保第3條知足就能夠了。 下面的圖片演示瞭如何完成這個配置:(注意:配置方法也適合用域名訪問的狀況)
另外,除了在IE中設置Intranet外,還能夠在訪問網站時,用計算機名代替IP地址或者域名, 那麼IE始終認爲是在訪問Intranet內的網站,此時也不會彈出登陸對話框。
在此,我想再囉嗦三句: 1. IE在集成Windows身份認證時,雖然不提示登陸對話框,可是不表示不安全,它會自動傳遞登陸憑據。 2. 這種行爲只有IE才能支持。(其它的瀏覽器只是會記住密碼,在實現上實際上是不同的。) 3. 集成Windows身份認證,也只適合在Intranet的環境中使用。
在上篇博客中,我演示瞭如何用代碼訪問一個使用Forms身份認證的網站中的受限頁面,方法是使用CookieContainer對象接收服務端生的登陸Cookie。 然而,在Windows身份認證的網站中,身份驗證的過程發生在IIS中,並且根本不使用Cookie保存登陸狀態,而是須要在請求時發送必要的身份驗證信息。
在使用代碼作爲客戶端訪問Web服務器時,咱們仍然須要使用HttpWebRequest對象。 爲了能讓HttpWebRequest在訪問IIS時發送必要的身份驗證信息,HttpWebRequest提供二個屬性均可以完成這個功能:
// 獲取或設置請求的身份驗證信息。
//
// 返回結果:
// 包含與該請求關聯的身份驗證憑據的 System.Net.ICredentials。默認爲 null。
public override ICredentials Credentials { get; set; } // 獲取或設置一個 System.Boolean 值,該值控制默認憑據是否隨請求一塊兒發送。 // // 返回結果: // 若是使用默認憑據,則爲 true;不然爲 false。默認值爲 false。 public override bool UseDefaultCredentials { get; set; }
下面是我準備的完整的示例代碼(注意代碼中的註釋):
static void Main(string[] args) { try { // 請把WindowsAuthWebSite1這個網站部署在IIS中, // 開啓Windows認證方式,並禁止匿名用戶訪問。 // 而後修改下面的訪問地址。 HttpWebRequest request = (HttpWebRequest)WebRequest.Create("http://localhost:33445/Default.aspx"); // 下面三行代碼,啓用任意一行都是能夠的。 request.UseDefaultCredentials = true; //request.Credentials = CredentialCache.DefaultCredentials; //request.Credentials = CredentialCache.DefaultNetworkCredentials; // 若是上面的三行代碼全被註釋了,那麼將會看到401的異常信息。 using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() ) { using( StreamReader sr = new StreamReader(response.GetResponseStream()) ) { Console.WriteLine(sr.ReadToEnd()); } } } catch( WebException wex ) { Console.WriteLine("====================================="); Console.WriteLine("異常發生了。"); Console.WriteLine("====================================="); Console.WriteLine(wex.Message); } }
其實關鍵部分仍是設置UseDefaultCredentials或者Credentials,代碼中的三種方法是有效的。 這三種方法的差異: 1. Credentials = CredentialCache.DefaultCredentials; 表示在發送請求會帶上當前用戶的身份驗證憑據。 2. UseDefaultCredentials = true; 此方法在內部會調用前面的方法,所以與前面的方法是同樣的。 3. Credentials = CredentialCache.DefaultNetworkCredentials; 是在.NET 2.0中引用的新方法。
關於DefaultCredentials和DefaultNetworkCredentials的更多差異,請看我整理的表格:
Credentials屬性 | 申明類型 | 實例類型 | .NET支持版本 |
DefaultCredentials | ICredentials | SystemNetworkCredential | 從1.0開始 |
DefaultNetworkCredentials | NetworkCredential | SystemNetworkCredential | 從2.0開始 |
三個類型的繼承關係: 1. NetworkCredential實現了ICredentials接口, 2. SystemNetworkCredential繼承自NetworkCredential。
在結束這篇博客以前,我想我應該感謝新蛋。 在新蛋的網絡環境中,讓我學會了使用Windows身份認證。 除了感謝以外,我如今還特別懷念 fl45 這個登陸名......