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

細(xì)說ASP.NET Windows身份認(rèn)證

開發(fā) 后端
Windows身份認(rèn)證做為ASP.NET的默認(rèn)認(rèn)證方式,與Forms身份認(rèn)證在許多基礎(chǔ)方面是一樣的。

要使用Windows身份認(rèn)證模式,需要在web.config設(shè)置:

  1. <authentication mode="Windows" /> 

Windows身份認(rèn)證做為ASP.NET的默認(rèn)認(rèn)證方式,與Forms身份認(rèn)證在許多基礎(chǔ)方面是一樣的。 上篇博客我說過:我認(rèn)為ASP.NET的身份認(rèn)證的最核心部分其實(shí)就是HttpContext.User這個(gè)屬性所指向的對象。 在接下來的部分,我將著重分析這個(gè)對象在二種身份認(rèn)證中有什么差別。

在ASP.NET身份認(rèn)證過程中,IPrincipal和IIdentity這二個(gè)接口有著非常重要的作用。前者定義用戶對象的基本功能,后者定義標(biāo)識對象的基本功能,不同的身份認(rèn)證方式得到的這二個(gè)接口的實(shí)例也是不同的。

ASP.NET Windows身份認(rèn)證是由WindowsAuthenticationModule實(shí)現(xiàn)的。 WindowsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中,使用從IIS傳遞到ASP.NET的Windows訪問令牌(Token)創(chuàng)建一個(gè)WindowsIdentity對象,Token通過調(diào)用context.WorkerRequest.GetUserToken()獲得,然后再根據(jù)WindowsIdentity 對象創(chuàng)建WindowsPrincipal對象,然后把它賦值給HttpContext.User。

在Forms身份認(rèn)證中,我們需要?jiǎng)?chuàng)建登錄頁面,讓用戶提交用戶名和密碼,然后檢查用戶名和密碼的正確性,接下來創(chuàng)建一個(gè)包含F(xiàn)ormsAuthenticationTicket對象的登錄Cookie供后續(xù)請求使用。 FormsAuthenticationModule在ASP.NET管線的AuthenticateRequest事件中,解析登錄Cookie并創(chuàng)建一個(gè)包含F(xiàn)ormsIdentity的GenericPrincipal對象,然后把它賦值給HttpContext.User。

上面二段話簡單了概括了二種身份認(rèn)證方式的工作方式。

我們可以發(fā)現(xiàn)它們存在以下差別:

1. Forms身份認(rèn)證需要Cookie表示登錄狀態(tài),Windows身份認(rèn)證則依賴于IIS

2. Windows身份認(rèn)證不需要我們設(shè)計(jì)登錄頁面,不用編寫登錄驗(yàn)證邏輯,因此更容易使用。

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

在Windows身份認(rèn)證中,驗(yàn)證工作主要是由IIS實(shí)現(xiàn)的,WindowsAuthenticationModule其實(shí)只是負(fù)責(zé)創(chuàng)建WindowsPrincipal和WindowsIdentity而已。順便介紹一下:Windows 身份驗(yàn)證又分為“NTLM 身份驗(yàn)證”和“Kerberos v5 身份驗(yàn)證”二種,關(guān)于這二種Windows身份認(rèn)證的更多說明可查看MSDN技術(shù)文章:解釋:ASP.NET 2.0 中的 Windows 身份驗(yàn)證。在我看來,IIS最終使用哪種Windows身份認(rèn)證方式并不影響我們的開發(fā)過程,因此本文不會(huì)討論這個(gè)話題。

根據(jù)我的實(shí)際經(jīng)驗(yàn)來看,使用Windows身份認(rèn)證時(shí),主要的開發(fā)工作將是根據(jù)登錄名從Active Directory獲取用戶信息。因?yàn)椋藭r(shí)不需要我們再設(shè)計(jì)登錄過程,IIS與ASP.NET已經(jīng)為我們準(zhǔn)備好了WindowsPrincipal和WindowsIdentity這二個(gè)與用戶身份相關(guān)的對象。

訪問 Active Directory

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

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

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

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

我們?nèi)绾沃喇?dāng)前電腦所使用的是哪個(gè)域名呢?

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

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

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

  1. private static string GetDomainName()  
  2. {  
  3.     // 注意:這段代碼需要在Windows XP及較新版本的操作系統(tǒng)中才能正常運(yùn)行。  
  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;  

當(dāng)構(gòu)造了DirectorySearcher對象后,我們便可以使用DirectorySearcher來執(zhí)行對Active Directory的搜索。

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

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

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

3. 調(diào)用FindOne() 方法獲取搜索結(jié)果。

下面的代碼演示了如何從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.     }  

結(jié)果如下:

在前面的代碼,我在搜索Active Directory時(shí),只搜索了"name,givenName,samaccountname,mail"這4個(gè)屬性。然而,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

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

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

  1. /// <summary>  
  2. /// 根據(jù)指定的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.     // 此時(shí)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身份認(rèn)證時(shí),IIS和WindowsAuthenticationModule已經(jīng)做了許多驗(yàn)證用戶的相關(guān)工作,雖然我們可以使用前面的代碼獲取到用戶的登錄名,但用戶的其它信息即需要我們自己來獲取。在實(shí)際使用Windows身份認(rèn)證時(shí),我們要做的事:基本上就是從Active Directory中根據(jù)用戶的登錄名獲取所需的各種信息。

比如:我的程序在運(yùn)行時(shí),還需要使用以下與用戶相關(guān)的信息:

  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.     /// 活動(dòng)目錄中的搜索路徑,也可根據(jù)實(shí)際情況來修改這個(gè)值。  
  5.     /// </summary>  
  6.     public static string DirectoryPath = "LDAP://" + GetDomainName();  
  7.  
  8.  
  9.     /// <summary>  
  10.     /// 獲取與指定HttpContext相關(guān)的用戶信息  
  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.     /// 根據(jù)指定的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.         // 此時(shí)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.     /// 根據(jù)登錄名查詢活動(dòng)目錄,獲取用戶信息。  
  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.         // 下面的代碼將根據(jù)登錄名查詢用戶在AD中的信息。  
  59.         // 為了提高性能,可以在此處增加一個(gè)緩存容器(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.             // 如果需要記錄異常,請?jiān)诖颂幪砑哟a。  
  83.         }  
  84.         return null;  
  85.     }  
  86.  
  87.  
  88.     private static string GetDomainName()  
  89.     {  
  90.         // 注意:這段代碼需要在Windows XP及較新版本的操作系統(tǒng)中才能正常運(yùn)行。  
  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.     當(dāng)前登錄全名:<%= 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.     當(dāng)前用戶還未登錄。  
  17. <% } %> 
  18. </body> 
  19. </html> 

程序運(yùn)行的效果如下:

另外,還可以從Active Directory查詢一個(gè)叫做memberof的屬性(它與Windows用戶組無關(guān)),有時(shí)候可以用它區(qū)分用戶,設(shè)計(jì)與權(quán)限相關(guān)的操作。

在設(shè)計(jì)數(shù)據(jù)持久化的表結(jié)構(gòu)時(shí),由于此時(shí)沒有“用戶表”,那么我們可以直接保存用戶的登錄名。剩下的開發(fā)工作就與Forms身份認(rèn)證沒有太多的差別了。

使用Active Directory驗(yàn)證用戶身份

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

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

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

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

要實(shí)現(xiàn)自己的登錄檢查,就需要使用這個(gè)構(gòu)造函數(shù)。以下是我寫用WinForm寫的一個(gè)登錄檢查的示例:

  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.         // 如果用戶名或者密碼不正確,也會(huì)拋出異常。  
  21.         MessageBox.Show(ex.Message, this.Text, MessageBoxButtons.OK, MessageBoxIcon.Stop);  
  22.     }  

程序運(yùn)行的效果如下:

安全上下文與用戶模擬

在ASP.NET Windows身份認(rèn)證環(huán)境中,與用戶相關(guān)的安全上下文對象保存在HttpContext.User屬性中,是一個(gè)類型為WindowsPrincipal的對象,我們還可以訪問HttpContext.User.Identity來獲取經(jīng)過身份認(rèn)證的用戶標(biāo)識,它是一個(gè)WindowsIdentity類型的對象。

在.NET Framework中,我們可以通過WindowsIdentity.GetCurrent()獲取與當(dāng)前線程相關(guān)的WindowsIdentity對象,這種方法獲取的是當(dāng)前運(yùn)行的Win32線程的安全上下文標(biāo)識。由于ASP.NET運(yùn)行在IIS進(jìn)程中,因此ASP.NET線程的安全標(biāo)識其實(shí)是從IIS的進(jìn)程中繼承的,所以此時(shí)用二種方法得到的WindowsIdentity對象其實(shí)是不同的。

在Windows操作系統(tǒng)中,許多權(quán)限檢查都是基于Win32線程的安全上下文標(biāo)識,于是前面所說的二種WindowsIdentity對象會(huì)造成編程模型的不一致問題,為了解決這個(gè)問題,ASP.NET提供了“模擬”功能,允許線程以特定的Windows帳戶的安全上下文來訪問資源。

為了能更好的理解模擬的功能,我準(zhǔn)備了一個(gè)示例(ShowWindowsIdentity.ashx):

  1. public class ShowWindowsIdentity : IHttpHandler {  
  2.       
  3.     public void ProcessRequest (HttpContext context) {  
  4.         // 要觀察【模擬】的影響,  
  5.         // 可以啟用,禁止web.config中的設(shè)置:<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中設(shè)置:

  1. <authentication mode="Windows" /> 

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

此時(shí),訪問ShowWindowsIdentity.ashx,將看到如下圖所示的結(jié)果:

現(xiàn)在修改一下web.config中設(shè)置:(注意:后面加了一句配置

  1. <authentication mode="Windows" /> 
  2. <identity impersonate="true"/> 

此時(shí),訪問ShowWindowsIdentity.ashx,將看到如下圖所示的結(jié)果:

說明:

1. FISH-SRV2003是我的計(jì)算機(jī)名。它在一個(gè)沒有域的環(huán)境中。

2. fish-li是我的一個(gè)Windows帳號的登錄名。

3. 網(wǎng)站部署在IIS6中,進(jìn)程以NETWORK SERVICE帳號運(yùn)行。

4. 打開網(wǎng)頁時(shí),我輸入的用戶名是fish-li

前面二張圖片的差異之處其實(shí)也就是ASP.NET的“模擬”所發(fā)揮的功能。

關(guān)于模擬,我想說四點(diǎn):

1. 在ASP.NET中,我們應(yīng)該訪問HttpContext.User.Identity獲取當(dāng)前用戶標(biāo)識,那么就不存在問題(此時(shí)可以不需要模擬),例如FileAuthorizationModule就是這樣處理的。

2. 模擬只是在ASP.NET應(yīng)用程序訪問Windows系統(tǒng)資源時(shí)需要應(yīng)用Windows的安全檢查功能才會(huì)有用。

3. Forms身份認(rèn)證也能配置模擬功能,但只能模擬一個(gè)Windows帳戶。

4. 絕大多數(shù)情況下是不需要模擬的。

在IIS中配置Windows身份認(rèn)證

與使用Forms身份認(rèn)證的程序不同,使用Windows身份認(rèn)證的程序需要額外的配置步驟。這個(gè)小節(jié)將主要介紹在IIS中配置Windows身份認(rèn)證,我將常用的IIS6和IIS7.5為例分別介紹這些配置。

IIS6的配置 請參考下圖:

 

IIS7.5的配置 請參考下圖:

注意:Windows身份認(rèn)證是需要安裝的,方法請參考下圖:

關(guān)于瀏覽器的登錄對話框問題

當(dāng)我們用瀏覽器訪問一個(gè)使用Windows身份認(rèn)證的網(wǎng)站時(shí),瀏覽器都會(huì)彈出一個(gè)對話框(左IE,右Safari):

此時(shí),要求我們輸入Windows的登錄帳號,然后交給IIS驗(yàn)證身份。

首次彈出這個(gè)對話框很正常:因?yàn)槌绦蛞?yàn)證用戶的身份。

然而,每次關(guān)閉瀏覽器下次重新打開頁面時(shí),又會(huì)出現(xiàn)此對話框,此時(shí)感覺就很不方便了。

雖然有些瀏覽器能記住用戶名和密碼,但我發(fā)現(xiàn)FireFox,Opera,Chrome仍然會(huì)彈出這個(gè)對話框,等待我們點(diǎn)擊確定,只有Safari才不會(huì)打擾用戶直接打開網(wǎng)頁。 IE的那個(gè)“記住我的密碼”復(fù)選框完全是個(gè)擺設(shè),它根本不會(huì)記住密碼!

因此,我所試過的所有瀏覽器中,只有Safari是最人性化的。

雖然在默認(rèn)情況下,雖然IE不會(huì)記住密碼,每次都需要再次輸入。

不過,IE卻可以支持不提示用戶輸入登錄帳號而直接打開網(wǎng)頁, 此時(shí)IE將使用用戶的當(dāng)前Windows登錄帳號傳遞給IIS驗(yàn)證身份。

要讓IE打開一個(gè)Windows身份認(rèn)證的網(wǎng)站不提示登錄對話框,必須滿足以下條件:

1. 必須在 IIS 的 Web 站點(diǎn)屬性中啟用 Windows 集成身份驗(yàn)證。

2. 客戶端和Web服務(wù)器都必須在基于Microsoft Windows的同一個(gè)域內(nèi)。

3. Internet Explorer 必須把所請求的 URL 視為 Intranet(本地)。

4. Internet Explorer 的 Intranet 區(qū)域的安全性設(shè)置必須設(shè)為“只在 Intranet 區(qū)域自動(dòng)登錄”。

5. 請求Web頁的用戶必須具有訪問該Web頁以及該Web頁中引用的所有對象的適當(dāng)?shù)奈募到y(tǒng)(NTFS)權(quán)限。

6. 用戶必須用域帳號登錄到Windows 。

在這幾個(gè)條件中,如果網(wǎng)站是在一個(gè)Windows域中運(yùn)行,除了第3條可能不滿足外,其它條件應(yīng)該都容易滿足(第4條是默認(rèn)值)。因此,要讓IE不提示輸入登錄帳號,只要確保第3條滿足就可以了。下面的圖片演示了如何完成這個(gè)配置:(注意:配置方法也適合用域名訪問的情況)

 

另外,除了在IE中設(shè)置Intranet外,還可以在訪問網(wǎng)站時(shí),用計(jì)算機(jī)名代替IP地址或者域名,那么IE始終認(rèn)為是在訪問Intranet內(nèi)的網(wǎng)站,此時(shí)也不會(huì)彈出登錄對話框。

在此,我想再啰嗦三句:

1. IE在集成Windows身份認(rèn)證時(shí),雖然不提示登錄對話框,但是不表示不安全,它會(huì)自動(dòng)傳遞登錄憑據(jù)。

2. 這種行為只有IE才能支持。(其它的瀏覽器只是會(huì)記住密碼,在實(shí)現(xiàn)上其實(shí)是不一樣的。)

3. 集成Windows身份認(rèn)證,也只適合在Intranet的環(huán)境中使用。

在客戶端代碼中訪問Windows身份認(rèn)證的頁面

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

在使用代碼做為客戶端訪問Web服務(wù)器時(shí),我們?nèi)匀恍枰褂肏ttpWebRequest對象。為了能讓HttpWebRequest在訪問IIS時(shí)發(fā)送必要的身份驗(yàn)證信息,HttpWebRequest提供二個(gè)屬性都可以完成這個(gè)功能:

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

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

  1. static void Main(string[] args)  
  2. {  
  3.     try {  
  4.         // 請把WindowsAuthWebSite1這個(gè)網(wǎng)站部署在IIS中,  
  5.         // 開啟Windows認(rèn)證方式,并禁止匿名用戶訪問。  
  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.         // 如果上面的三行代碼全被注釋了,那么將會(huì)看到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("異常發(fā)生了。");  
  25.         Console.WriteLine("=====================================");  
  26.         Console.WriteLine(wex.Message);  
  27.     }  

其實(shí)關(guān)鍵部分還是設(shè)置UseDefaultCredentials或者Credentials,代碼中的三種方法是有效的。

這三種方法的差別:
1. Credentials = CredentialCache.DefaultCredentials; 表示在發(fā)送請求會(huì)帶上當(dāng)前用戶的身份驗(yàn)證憑據(jù)。
2. UseDefaultCredentials = true; 此方法在內(nèi)部會(huì)調(diào)用前面的方法,因此與前面的方法是一樣的。
3. Credentials = CredentialCache.DefaultNetworkCredentials; 是在.NET 2.0中引用的新方法。

關(guān)于DefaultCredentials和DefaultNetworkCredentials的更多差別,請看我整理的表格:

Credentials屬性 申明類型 實(shí)例類型 .NET支持版本
DefaultCredentials ICredentials SystemNetworkCredential 從1.0開始
DefaultNetworkCredentials NetworkCredential SystemNetworkCredential 從2.0開始

三個(gè)類型的繼承關(guān)系:
1. NetworkCredential實(shí)現(xiàn)了ICredentials接口,
2. SystemNetworkCredential繼承自NetworkCredential。

在結(jié)束這篇博客之前,我想我應(yīng)該感謝新蛋。

在新蛋的網(wǎng)絡(luò)環(huán)境中,讓我學(xué)會(huì)了使用Windows身份認(rèn)證。

除了感謝之外,我現(xiàn)在還特別懷念 fl45 這個(gè)登錄名......

點(diǎn)擊此處下載示例代碼

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

 

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2012-04-16 09:54:26

2009-12-10 17:47:01

ASP.NET 2.0

2009-07-29 12:55:44

ASP.NET身份驗(yàn)證

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認(rèn)證Form表單

2021-02-17 08:51:55

cookie身份驗(yàn)證

2009-07-29 15:51:29

ASP.NET中執(zhí)行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組件設(shè)計(jì)

2009-07-29 17:11:25

ASP.NET ISA

2009-07-28 12:42:17

.NET關(guān)機(jī)代碼

2009-07-29 16:08:07

ASP和ASP.NET

2012-06-04 09:36:50

2009-07-29 16:47:40

ASP.NET表單身份

2024-05-06 00:00:00

ASP.NET授權(quán)機(jī)制

2009-07-28 09:02:32

asp.net aja
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产成人福利视频在线观看 | 欧美日韩最新 | 在线a视频网站 | 一级毛片在线播放 | 欧美日韩国产一区二区三区 | 欧美日韩中文字幕 | 毛片免费看 | 日日干天天操 | 黄色精品 | 欧美一区二区三区视频在线观看 | 久久久高清 | 国产一区二区在线观看视频 | 国精日本亚洲欧州国产中文久久 | 99国产精品一区二区三区 | 亚洲精品久久久一区二区三区 | 日韩欧美一级精品久久 | 久久av一区 | 一片毛片 | 在线观看视频你懂得 | 你懂的国产 | 亚洲一av | 爱爱爱av | 成人免费视频久久 | 国产在线永久免费 | 久久久久国产精品一区二区 | 欧美日韩亚洲国产综合 | 亚洲视频三区 | 在线免费观看毛片 | 精品国产乱码久久久久久闺蜜 | 永久免费在线观看 | 日韩久久久一区二区 | 国产精品入口久久 | 欧美在线 | 在线视频国产一区 | 国产色婷婷精品综合在线手机播放 | 九九免费观看视频 | 美女一区二区在线观看 | 亚洲精品一区二 | 亚洲第一成人影院 | 精品一区二区观看 | 激情五月婷婷综合 |