成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

細說ASP.NET Windows身份認證

開發 后端
Windows身份認證做為ASP.NET的默認認證方式,與Forms身份認證在許多基礎方面是一樣的。

要使用Windows身份認證模式,需要在web.config設置:

  1. <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身份認證不需要我們設計登錄頁面,不用編寫登錄驗證邏輯,因此更容易使用。

在授權階段,UrlAuthorizationModule仍然會根據當前用戶檢查將要訪問的資源是否得到許可。接下來,FileAuthorizationModule檢查 HttpContext.User.Identity 屬性中的 IIdentity 對象是否是 WindowsIdentity 類的一個實例。如果 IIdentity 對象不是 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類停止處理。如果存在 WindowsIdentity 類的一個實例,則 FileAuthorizationModule 類調用 AccessCheck Win32 函數(通過 P/Invoke)來確定是否授權經過身份驗證的客戶端訪問請求的文件。如果該文件的安全描述符的隨機訪問控制列表 (DACL) 中至少包含一個 Read 訪問控制項 (ACE),則允許該請求繼續。否則,FileAuthorizationModule 類調用 HttpApplication.CompleteRequest 方法并將狀態碼 401 返回到客戶端。

在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這二個與用戶身份相關的對象。

訪問 Active Directory

我們通常使用LDAP協議來訪問Active Directory,在.net framework中提供了DirectoryEntry和DirectorySearcher這二個類型讓我們可以方便地從托管代碼中訪問 Active Directory 域服務。

如果我們要在"test.corp”這個域中搜索某個用戶信息,我們可以使用下面的語句構造一個DirectoryEntry對象:

  1. DirectoryEntry entry = new DirectoryEntry("LDAP://test.corp"); 

在這段代碼中,我采用硬編碼的方式把域名寫進了代碼。

我們如何知道當前電腦所使用的是哪個域名呢?

答案是:查看“我的電腦”的屬性對話框:

注意:這個域名不一定與System.Environment.UserDomainName相同。

除了可以查看“我的電腦”的屬性對話框外,我們還可以使用代碼的方式獲取當前電腦所使用的域名:

  1. private static string GetDomainName()  
  2. {  
  3.     // 注意:這段代碼需要在Windows XP及較新版本的操作系統中才能正常運行。  
  4.     SelectQuery query = new SelectQuery("Win32_ComputerSystem");  
  5.     using( ManagementObjectSearcher searcher = new ManagementObjectSearcher(query) ) {  
  6.         foreach( ManagementObject mo in searcher.Get() ) {  
  7.             if( (bool)mo["partofdomain"] )  
  8.                 return mo["domain"].ToString();  
  9.         }  
  10.     }  
  11.     return null;  

當構造了DirectorySearcher對象后,我們便可以使用DirectorySearcher來執行對Active Directory的搜索。

我們可以使用下面的步驟來執行搜索:

1. 設置 DirectorySearcher.Filter 指示LDAP格式篩選器,這是一個字符串。

2. 多次調用PropertiesToLoad.Add() 設置搜索過程中要檢索的屬性列表。

3. 調用FindOne() 方法獲取搜索結果。

下面的代碼演示了如何從Active Directory中搜索登錄名為“fl45”的用戶信息:

  1. static void Main(string[] args)  
  2. {  
  3.     Console.WriteLine(Environment.UserDomainName);  
  4.     Console.WriteLine(Environment.UserName);  
  5.     Console.WriteLine("------------------------------------------------");  
  6.  
  7.     ShowUserInfo("fl45", GetDomainName());  
  8. }  
  9.  
  10. private static string AllProperties = "name,givenName,samaccountname,mail";  
  11.  
  12. public static void ShowUserInfo(string loginName, string domainName)  
  13. {  
  14.     ifstring.IsNullOrEmpty(loginName) || string.IsNullOrEmpty(domainName) )  
  15.         return;  
  16.  
  17.     string[] properties = AllProperties.Split(new char[] { '\r''\n'',' },   
  18.                         StringSplitOptions.RemoveEmptyEntries);  
  19.  
  20.     try {  
  21.         DirectoryEntry entry = new DirectoryEntry("LDAP://" + domainName);  
  22.         DirectorySearcher search = new DirectorySearcher(entry);  
  23.         search.Filter = "(samaccountname=" + loginName + ")";  
  24.  
  25.         foreachstring p in properties )  
  26.             search.PropertiesToLoad.Add(p);  
  27.  
  28.         SearchResult result = search.FindOne();  
  29.  
  30.         if( result != null ) {  
  31.             foreachstring p in properties ) {  
  32.                 ResultPropertyValueCollection collection = result.Properties[p];  
  33.                 forint i = 0; i < collection.Count; i++ )  
  34.                     Console.WriteLine(p + ": " + collection[i]);  
  35.             }  
  36.         }  
  37.     }  
  38.     catch( Exception ex ) {  
  39.         Console.WriteLine(ex.ToString());  
  40.     }  

結果如下:

在前面的代碼,我在搜索Active Directory時,只搜索了"name,givenName,samaccountname,mail"這4個屬性。然而,LDAP還支持更多的屬性,我們可以使用下面的代碼查看更多的用戶信息:

  1.         private static string AllProperties = @"  
  2. homemdb  
  3. distinguishedname  
  4. countrycode  
  5. cn  
  6. lastlogoff  
  7. mailnickname  
  8. dscorepropagationdata  
  9. msexchhomeservername  
  10. msexchmailboxsecuritydescriptor  
  11. msexchalobjectversion  
  12. usncreated  
  13. objectguid  
  14. whenchanged  
  15. memberof  
  16. msexchuseraccountcontrol  
  17. accountexpires  
  18. displayname  
  19. primarygroupid  
  20. badpwdcount  
  21. objectclass  
  22. instancetype  
  23. objectcategory  
  24. samaccounttype  
  25. whencreated  
  26. lastlogon  
  27. useraccountcontrol  
  28. physicaldeliveryofficename  
  29. samaccountname  
  30. usercertificate  
  31. givenname  
  32. mail  
  33. userparameters  
  34. adspath  
  35. homemta  
  36. msexchmailboxguid  
  37. pwdlastset  
  38. logoncount  
  39. codepage  
  40. name  
  41. usnchanged  
  42. legacyexchangedn  
  43. proxyaddresses  
  44. department  
  45. userprincipalname  
  46. badpasswordtime  
  47. objectsid  
  48. sn  
  49. mdbusedefaults  
  50. telephonenumber  
  51. showinaddressbook  
  52. msexchpoliciesincluded  
  53. textencodedoraddress  
  54. lastlogontimestamp  
  55. company  
  56. "; 

在ASP.NET中訪問Active Directory

前面我在一個控制臺程序中演示了訪問Active Directory的方法,通過示例我們可以看到:在代碼中,我用Environment.UserName就可以得到當前用戶的登錄名。然而,如果是在ASP.NET程序中,訪問Environment.UserName就很有可能得不到真正用戶登錄名。因為:Environment.UserName是使用WIN32API中的GetUserName獲取線程相關的用戶名,但ASP.NET運行在IIS中,線程相關的用戶名就不一定是客戶端的用戶名了。不過,ASP.NET可以模擬用戶方式運行,通過這種方式才可以得到正確的結果。關于“模擬”的話題在本文的后面部分有說明。

在ASP.NET中,為了能可靠的獲取登錄用戶的登錄名,我們可以使用下面的代碼:

  1. /// <summary>  
  2. /// 根據指定的HttpContext對象,獲取登錄名。  
  3. /// </summary>  
  4. /// <param name="context"></param>  
  5. /// <returns></returns>  
  6. public static string GetUserLoginName(HttpContext context)  
  7. {  
  8.     if( context == null )  
  9.         return null;  
  10.  
  11.     if( context.Request.IsAuthenticated == false )  
  12.         return null;  
  13.  
  14.     string userName = context.User.Identity.Name;  
  15.     // 此時userName的格式為:UserDomainName\LoginName  
  16.     // 我們只需要后面的LoginName就可以了。  
  17.  
  18.     string[] array = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);  
  19.     if( array.Length == 2 )  
  20.         return array[1];  
  21.  
  22.     return null;  

在ASP.NET中使用Windows身份認證時,IIS和WindowsAuthenticationModule已經做了許多驗證用戶的相關工作,雖然我們可以使用前面的代碼獲取到用戶的登錄名,但用戶的其它信息即需要我們自己來獲取。在實際使用Windows身份認證時,我們要做的事:基本上就是從Active Directory中根據用戶的登錄名獲取所需的各種信息。

比如:我的程序在運行時,還需要使用以下與用戶相關的信息:

  1. public sealed class UserInfo  
  2. {  
  3.     public string GivenName;  
  4.     public string FullName;  
  5.     public string Email;  

那么,我們可以使用這樣的代碼來獲取所需的用戶信息:

  1. public static class UserHelper  
  2. {  
  3.     /// <summary>  
  4.     /// 活動目錄中的搜索路徑,也可根據實際情況來修改這個值。  
  5.     /// </summary>  
  6.     public static string DirectoryPath = "LDAP://" + GetDomainName();  
  7.  
  8.  
  9.     /// <summary>  
  10.     /// 獲取與指定HttpContext相關的用戶信息  
  11.     /// </summary>  
  12.     /// <param name="context"></param>  
  13.     /// <returns></returns>  
  14.     public static UserInfo GetCurrentUserInfo(HttpContext context)  
  15.     {  
  16.         string loginName = GetUserLoginName(context);  
  17.         ifstring.IsNullOrEmpty(loginName) )  
  18.             return null;  
  19.  
  20.         return GetUserInfoByLoginName(loginName);  
  21.     }  
  22.  
  23.     /// <summary>  
  24.     /// 根據指定的HttpContext對象,獲取登錄名。  
  25.     /// </summary>  
  26.     /// <param name="context"></param>  
  27.     /// <returns></returns>  
  28.     public static string GetUserLoginName(HttpContext context)  
  29.     {  
  30.         if( context == null )  
  31.             return null;  
  32.  
  33.         if( context.Request.IsAuthenticated == false )  
  34.             return null;  
  35.  
  36.         string userName = context.User.Identity.Name;  
  37.         // 此時userName的格式為:UserDomainName\LoginName  
  38.         // 我們只需要后面的LoginName就可以了。  
  39.  
  40.         string[] array = userName.Split(new char[] { '\\' }, StringSplitOptions.RemoveEmptyEntries);  
  41.         if( array.Length == 2 )  
  42.             return array[1];  
  43.  
  44.         return null;  
  45.     }  
  46.       
  47.  
  48.     /// <summary>  
  49.     /// 根據登錄名查詢活動目錄,獲取用戶信息。  
  50.     /// </summary>  
  51.     /// <param name="loginName"></param>  
  52.     /// <returns></returns>  
  53.     public static UserInfo GetUserInfoByLoginName(string loginName)  
  54.     {  
  55.         ifstring.IsNullOrEmpty(loginName) )  
  56.             return null;  
  57.  
  58.         // 下面的代碼將根據登錄名查詢用戶在AD中的信息。  
  59.         // 為了提高性能,可以在此處增加一個緩存容器(Dictionary or Hashtable)。  
  60.  
  61.         try {  
  62.             DirectoryEntry entry = new DirectoryEntry(DirectoryPath);  
  63.             DirectorySearcher search = new DirectorySearcher(entry);  
  64.             search.Filter = "(SAMAccountName=" + loginName + ")";  
  65.  
  66.             search.PropertiesToLoad.Add("givenName");  
  67.             search.PropertiesToLoad.Add("cn");  
  68.             search.PropertiesToLoad.Add("mail");  
  69.             // 如果還需要從AD中獲取其它的用戶信息,請參考ActiveDirectoryDEMO  
  70.  
  71.             SearchResult result = search.FindOne();  
  72.  
  73.             if( result != null ) {  
  74.                 UserInfo info = new UserInfo();  
  75.                 info.GivenName = result.Properties["givenName"][0].ToString();  
  76.                 info.FullName = result.Properties["cn"][0].ToString();  
  77.                 info.Email = result.Properties["mail"][0].ToString();  
  78.                 return info;  
  79.             }  
  80.         }  
  81.         catch {  
  82.             // 如果需要記錄異常,請在此處添加代碼。  
  83.         }  
  84.         return null;  
  85.     }  
  86.  
  87.  
  88.     private static string GetDomainName()  
  89.     {  
  90.         // 注意:這段代碼需要在Windows XP及較新版本的操作系統中才能正常運行。  
  91.         SelectQuery query = new SelectQuery("Win32_ComputerSystem");  
  92.         using( ManagementObjectSearcher searcher = new ManagementObjectSearcher(query) ) {  
  93.             foreach( ManagementObject mo in searcher.Get() ) {  
  94.                 if( (bool)mo["partofdomain"] )  
  95.                     return mo["domain"].ToString();  
  96.             }  
  97.         }  
  98.         return null;  
  99.     }  
  100.  

使用UserHelper的頁面代碼:

  1. <html xmlns="http://www.w3.org/1999/xhtml"> 
  2. <head> 
  3.     <title>WindowsAuthentication DEMO  - http://www.cnblogs.com/fish-li/</title> 
  4. </head> 
  5. <body> 
  6. <% if( Request.IsAuthenticated ) { %> 
  7.     當前登錄全名:<%= Context.User.Identity.Name.HtmlEncode()%> <br /> 
  8.       
  9.     <% var user = UserHelper.GetCurrentUserInfo(Context); %> 
  10.     <% if( user != null ) { %> 
  11.         用戶短名:<%= user.GivenName.HtmlEncode()%> <br /> 
  12.         用戶全名:<%= user.FullName.HtmlEncode() %> <br /> 
  13.         郵箱地址:<%= user.Email.HtmlEncode() %> 
  14.     <% } %>      
  15. <% } else { %> 
  16.     當前用戶還未登錄。  
  17. <% } %> 
  18. </body> 
  19. </html> 

程序運行的效果如下:

另外,還可以從Active Directory查詢一個叫做memberof的屬性(它與Windows用戶組無關),有時候可以用它區分用戶,設計與權限相關的操作。

在設計數據持久化的表結構時,由于此時沒有“用戶表”,那么我們可以直接保存用戶的登錄名。剩下的開發工作就與Forms身份認證沒有太多的差別了。

使用Active Directory驗證用戶身份

前面介紹了ASP.NET Windows身份認證,在這種方式下,IIS和WindowsAuthenticationModule為我們實現了用戶身份認證的過程。然而,有時可能由于各種原因,需要我們以編程的方式使用Active Directory驗證用戶身份,比如:在WinForm程序,或者其它的驗證邏輯。

我們不僅可以從Active Directory中查詢用戶信息,也可以用它來實現驗證用戶身份,這樣便可以實現自己的登錄驗證邏輯。

不管是如何使用Active Directory,我們都需要使用DirectoryEntry和DirectorySearcher這二個對象。 DirectoryEntry還提供一個構造函數可讓我們輸入用戶名和密碼:

  1. // 摘要:  
  2. //     初始化 System.DirectoryServices.DirectoryEntry 類的新實例。  
  3. //  
  4. // 參數:  
  5. //   Password:  
  6. //     在對客戶端進行身份驗證時使用的密碼。DirectoryEntry.Password 屬性初始化為該值。  
  7. //  
  8. //   username:  
  9. //     在對客戶端進行身份驗證時使用的用戶名。DirectoryEntry.Username 屬性初始化為該值。  
  10. //  
  11. //   Path:  
  12. //     此 DirectoryEntry 的路徑。DirectoryEntry.Path 屬性初始化為該值。  
  13. public DirectoryEntry(string path, string username, string password); 

要實現自己的登錄檢查,就需要使用這個構造函數。以下是我寫用WinForm寫的一個登錄檢查的示例:

  1. private void btnLogin_Click(object sender, EventArgs e)  
  2. {  
  3.     if( txtUsername.Text.Length == 0 || txtPassword.Text.Length == 0 ) {  
  4.         MessageBox.Show("用戶名或者密碼不能為空。"this.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);  
  5.         return;  
  6.     }  
  7.  
  8.     string ldapPath = "LDAP://" + GetDomainName();  
  9.     string domainAndUsername = Environment.UserDomainName + "\\" + txtUsername.Text;  
  10.     DirectoryEntry entry = new DirectoryEntry(ldapPath, domainAndUsername, txtPassword.Text);  
  11.  
  12.     DirectorySearcher search = new DirectorySearcher(entry);  
  13.  
  14.     try {  
  15.         SearchResult result = search.FindOne();  
  16.  
  17.         MessageBox.Show("登錄成功。"this.Text, MessageBoxButtons.OK, MessageBoxIcon.Information);  
  18.     }  
  19.     catch( Exception ex ) {  
  20.         // 如果用戶名或者密碼不正確,也會拋出異常。  
  21.         MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop);  
  22.     }  

程序運行的效果如下:

安全上下文與用戶模擬

在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):

  1. public class ShowWindowsIdentity : IHttpHandler {  
  2.       
  3.     public void ProcessRequest (HttpContext context) {  
  4.         // 要觀察【模擬】的影響,  
  5.         // 可以啟用,禁止web.config中的設置:<identity impersonate="true"/>  
  6.           
  7.         context.Response.ContentType = "text/plain";  
  8.  
  9.         context.Response.Write(Environment.UserDomainName + "\\" + Environment.UserName + "\r\n");  
  10.           
  11.         WindowsPrincipal winPrincipal = (WindowsPrincipal)HttpContext.Current.User;  
  12.         context.Response.Write(string.Format("HttpContext.Current.User.Identity: {0}, {1}\r\n",   
  13.                 winPrincipal.Identity.AuthenticationType, winPrincipal.Identity.Name));  
  14.           
  15.         WindowsPrincipal winPrincipal2 = (WindowsPrincipal)Thread.CurrentPrincipal;  
  16.         context.Response.Write(string.Format("Thread.CurrentPrincipal.Identity: {0}, {1}\r\n",  
  17.                 winPrincipal2.Identity.AuthenticationType, winPrincipal2.Identity.Name));  
  18.  
  19.         WindowsIdentity winId = WindowsIdentity.GetCurrent();  
  20.         context.Response.Write(string.Format("WindowsIdentity.GetCurrent(): {0}, {1}",  
  21.                 winId.AuthenticationType, winId.Name));  
  22.     } 

首先,在web.config中設置:

  1. <authentication mode="Windows" /> 

注意:要把網站部署在IIS中,否則看不出效果。

此時,訪問ShowWindowsIdentity.ashx,將看到如下圖所示的結果:

現在修改一下web.config中設置:(注意:后面加了一句配置

  1. <authentication mode="Windows" /> 
  2. <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. 絕大多數情況下是不需要模擬的。

在IIS中配置Windows身份認證

與使用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的環境中使用。

在客戶端代碼中訪問Windows身份認證的頁面

在上篇博客中,我演示了如何用代碼訪問一個使用Forms身份認證的網站中的受限頁面,方法是使用CookieContainer對象接收服務端生的登錄Cookie。然而,在Windows身份認證的網站中,身份驗證的過程發生在IIS中,而且根本不使用Cookie保存登錄狀態,而是需要在請求時發送必要的身份驗證信息。

在使用代碼做為客戶端訪問Web服務器時,我們仍然需要使用HttpWebRequest對象。為了能讓HttpWebRequest在訪問IIS時發送必要的身份驗證信息,HttpWebRequest提供二個屬性都可以完成這個功能:

  1. // 獲取或設置請求的身份驗證信息。  
  2. //  
  3. // 返回結果:  
  4. //     包含與該請求關聯的身份驗證憑據的 System.Net.ICredentials。默認為 null。  
  5. public override ICredentials Credentials { getset; }  
  6.  
  7.  
  8. // 獲取或設置一個 System.Boolean 值,該值控制默認憑據是否隨請求一起發送。  
  9. //  
  10. // 返回結果:  
  11. //     如果使用默認憑據,則為 true;否則為 false。默認值為 false。  
  12. public override bool UseDefaultCredentials { getset; } 

下面是我準備的完整的示例代碼(注意代碼中的注釋)

  1. static void Main(string[] args)  
  2. {  
  3.     try {  
  4.         // 請把WindowsAuthWebSite1這個網站部署在IIS中,  
  5.         // 開啟Windows認證方式,并禁止匿名用戶訪問。  
  6.         // 然后修改下面的訪問地址。  
  7.         HttpWebRequest request =   
  8.             (HttpWebRequest)WebRequest.Create("http://localhost:33445/Default.aspx");  
  9.  
  10.         // 下面三行代碼,啟用任意一行都是可以的。  
  11.         request.UseDefaultCredentials = true;  
  12.         //request.Credentials = CredentialCache.DefaultCredentials;  
  13.         //request.Credentials = CredentialCache.DefaultNetworkCredentials;  
  14.         // 如果上面的三行代碼全被注釋了,那么將會看到401的異常信息。  
  15.  
  16.         using( HttpWebResponse response = (HttpWebResponse)request.GetResponse() ) {  
  17.             using( StreamReader sr = new StreamReader(response.GetResponseStream()) ) {  
  18.                 Console.WriteLine(sr.ReadToEnd());  
  19.             }  
  20.         }  
  21.     }  
  22.     catch( WebException wex ) {  
  23.         Console.WriteLine("=====================================");  
  24.         Console.WriteLine("異常發生了。");  
  25.         Console.WriteLine("=====================================");  
  26.         Console.WriteLine(wex.Message);  
  27.     }  

其實關鍵部分還是設置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 這個登錄名......

點擊此處下載示例代碼

原文鏈接:http://www.cnblogs.com/fish-li/archive/2012/05/07/2486840.html

 

責任編輯:彭凡 來源: 博客園
相關推薦

2012-04-16 09:54:26

2009-12-10 17:47:01

ASP.NET 2.0

2009-07-29 12:55:44

ASP.NET身份驗證

2009-08-03 14:22:33

什么是ASP.NET

2009-07-28 17:17:19

ASP.NET概述

2011-05-23 10:37:03

2009-07-22 17:45:35

ASP.NET教程

2009-07-23 16:59:31

ASP.NET認證Form表單

2021-02-17 08:51:55

cookie身份驗證

2009-07-29 15:51:29

ASP.NET中執行w

2009-07-27 12:22:03

ASP.NET和ASPASP.NET入門教程

2009-07-28 16:31:03

Windows 200

2009-08-10 13:32:15

ASP.NET TimASP.NET組件設計

2009-07-29 17:11:25

ASP.NET ISA

2009-07-28 12:42:17

.NET關機代碼

2009-07-29 16:08:07

ASP和ASP.NET

2009-07-28 09:02:32

asp.net aja

2009-08-03 17:35:07

ASP.NET WebASP.NET編程工具

2012-06-04 09:36:50

2009-07-29 16:47:40

ASP.NET表單身份
點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 一级黄色网页 | 国产精品久久久久久久久久久免费看 | 99亚洲| 久久久www成人免费精品张筱雨 | 亚洲精品一区二区三区在线 | 亚洲精品乱码8久久久久久日本 | 久久久久久亚洲 | 国产精品久久久久久中文字 | 婷婷在线免费 | 青青草一区 | 欧美一区2区三区4区公司 | 欧美八区| 鲁一鲁资源影视 | 成人亚洲视频 | 91国产视频在线观看 | 国产一级免费视频 | 北条麻妃一区二区三区在线观看 | 欧洲色综合 | 亚洲免费影院 | 美女爽到呻吟久久久久 | 欧美日韩网站 | 精品一区二区三区免费视频 | 国产精品中文在线 | japan25hdxxxx日本| 欧美 日韩 亚洲91麻豆精品 | 一区二区三区视频在线观看 | 亚洲成人免费在线观看 | 亚洲精品一区二三区不卡 | 亚洲精品一区二区另类图片 | 亚洲高清免费观看 | 日本久草 | www.狠狠干 | 国产精品美女久久久久久免费 | 国产高清精品一区 | 久久久久久综合 | 五月婷婷 六月丁香 | 天天操天天干天天透 | 喷水毛片 | 狠狠干av | 欧美日韩在线观看视频网站 | 天天天操操操 |