网站导航免费论文 原创论文 论文搜索 原创论文 网学软件 学术大家 资料中心 会员中心 问题解答 原创论文 大学论文导航 设计下载 最新论文 下载排行 原创论文 论文源代码
返回网学首页
网学联系
最新论文 推荐专题 热门论文 素材专题
当前位置: 网学 > 编程文档 > ASP.net > 正文

细说ASP.NET Windows身份认证

来源:http://myeducs.cn 联系QQ:点击这里给我发消息 作者: 用户投稿 来源: 网络 发布时间: 13/01/05
果如下:

498)this.width=498;'' onmousewheel = ''javascript:return big(this)'' alt="" src="/uploadfile/201301/5/95151816363.png" />

在前面的代码,我在搜索Active Directory时,只搜索了"name,givenName,samaccountname,mail"这4个属性。然而,LDAP还支持更多的属性,我们可以使用下面的代码查看更多的用户信息: 498)this.width=498;'' onmousewheel = ''javascript:return big(this)'' alt="" src="/uploadfile/201301/5/DF151816784.png" />

  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;  

那么,我们可以使用这样的代码来获取所需的用户信息: 498)this.width=498;'' onmousewheel = ''javascript:return big(this)'' alt="" src="/uploadfile/201301/5/DF151816784.png" />

  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> 

程序运行的效果如下:

498)this.width=498;'' onmousewheel = ''javascript:return big(this)'' alt="" src="http://images.myeducs.cn/files/uploadimg/20120507/1452184.png" />

另外,还可以从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.     }  

程序运行的效果如下:

498)this.width=498;'' onmousewheel = ''javascript:return big(this)'' alt="" src="/uploadfile/201301/5/C7151816530.png" />

安全上下文与用户模拟

在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提供了“模拟”功能,

版权所有 QQ:3710167 邮箱:3710167@qq.com 网学网 [Myeducs.cn] 您电脑的分辨率是 1280 x 720 像素
Copyright 2008-2015 myeducs.Cn www.myeducs.Cn All Rights Reserved 湘ICP备09003080号