如何进行身份验证 Active Directory,通过使用 Forms 身份验证和 Visual C#.net

文章翻译 文章翻译
文章编号: 316748 - 查看本文应用于的产品
这篇文章到下面的 Microsoft.net 框架类库命名空间的引用:
  • System.Text
  • System.DirectoryServices
  • System.Security.Principal
  • System.Web.Security
展开全部 | 关闭全部

本文内容

概要

本分步指南介绍演示如何将 ASP.NET 应用程序可以使用 Forms 身份验证,以允许用户进行身份验证对 Active Directory,通过使用轻型目录访问协议 (LDAP)。用户已通过身份验证并已重定向之后,可以使用的 Global.asax 文件 Application_AuthenticateRequest 方法以流的整个请求在 HttpContext.User 属性中存储 GenericPrincipal 对象。

在 Visual C#.net 中创建一个 ASP.NET Web 应用程序

请按照下列步骤创建新的 ASP.NET Web 应用程序名为 Visual C#.net 中的 FormsAuthAd 操作:
  1. 启动 Microsoft Visual Studio.net。
  2. 文件 菜单上指向 新建,然后单击 项目
  3. 项目类型 框中,单击 Visual C# 项目,然后单击 模板 下的 ASP.NET Web 应用程序
  4. 位置 框替换 FormsAuthAd WebApplication1。
  5. 单击 确定
  6. 用鼠标右键单击在解决方案资源管理器,引用 节点,然后单击 添加引用
  7. 添加引用 对话框 .net 选项卡上单击 System.DirectoryServices.dll 并单击 选择,然后单击 确定

编写验证代码

请按照下列步骤创建一个新的类文件,名为 LdapAuthentication.cs 操作:
  1. 在解决方案资源管理器中,用鼠标右键单击该项目节点,指向 添加,然后单击 添加新项
  2. 模板 下,单击
  3. 名称 框中键入 LdapAuthentication.cs,然后单击 打开
  4. LdapAuthentication.cs 文件中的现有代码替换下面的代码
    using System;
    using System.Text;
    using System.Collections;
    using System.DirectoryServices;
    
    namespace FormsAuth
    {	
      public class LdapAuthentication
      {
        private String _path;
        private String _filterAttribute;
    
        public LdapAuthentication(String path)
        {
          _path = path;
        }
    		
        public bool IsAuthenticated(String domain, String username, String pwd)
        {
          String domainAndUsername = domain + @"\" + username;
          DirectoryEntry entry = new DirectoryEntry(_path, domainAndUsername, pwd);
    			
          try
          {	//Bind to the native AdsObject to force authentication.			
             Object obj = entry.NativeObject;
    
    	DirectorySearcher search = new DirectorySearcher(entry);
    
    	search.Filter = "(SAMAccountName=" + username + ")";
    	search.PropertiesToLoad.Add("cn");
    	SearchResult result = search.FindOne();
    
    	if(null == result)
    	{
      	  return false;
    	}
    
    	//Update the new path to the user in the directory.
    	_path = result.Path;
    	_filterAttribute = (String)result.Properties["cn"][0];
          }
          catch (Exception ex)
          {
            throw new Exception("Error authenticating user. " + ex.Message);
          }
    
    	return true;
         }
    
         public String GetGroups()
         {
           DirectorySearcher search = new DirectorySearcher(_path);
           search.Filter = "(cn=" + _filterAttribute + ")";
           search.PropertiesToLoad.Add("memberOf");
           StringBuilder groupNames = new StringBuilder();
    
           try
           {
             SearchResult result = search.FindOne();
    
    	 int propertyCount = result.Properties["memberOf"].Count;
    
       	 String dn;
    	 int equalsIndex, commaIndex;
    				
    	 for(int propertyCounter = 0; propertyCounter < propertyCount; propertyCounter++)
    	 {
    	   dn = (String)result.Properties["memberOf"][propertyCounter];
    
        	   equalsIndex = dn.IndexOf("=", 1);
    	   commaIndex = dn.IndexOf(",", 1);
    	   if(-1 == equalsIndex)
    	   {
    	     return null;
         	   }
    
               groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1));
    	   groupNames.Append("|");
    
        	 }
           }
           catch(Exception ex)
           {
             throw new Exception("Error obtaining group names. " + ex.Message);
           }			
           return groupNames.ToString();
         }
       }
    }
    					
身份验证代码接受域、 用户名、 将密码和在 Active Directory 中树的路径。此代码使用 LDAP 目录提供程序。

在 Logon.aspx 页代码调用 LdapAuthentication.IsAuthenticated 方法,并从用户收集凭据中传递。然后,DirectoryEntry 对象创建与目录树、 用户名称和密码路径。用户名称必须以"域 \ 用户名"格式。 DirectoryEntry 对象然后尝试通过获取 NativeObject 属性强制 AdsObject 绑定。如果成功,CN 属性中的为用户获取通过创建 DirectorySearcher 对象并 SAMAccountName 进行筛选。将对用户进行身份验证后,IsAuthenticated 方法, 返回 true。

若要获取该用户所属的组的列表,此代码调用 LdapAuthentication.GetGroups 的方法。LdapAuthentication.GetGroups 方法获取通过创建一个 DirectorySearcher 对象,并根据 memberOf 属性筛选用户所属的安全和分发组的列表。此方法返回由管道 (|) 分隔的组的列表。

请注意 LdapAuthentication.GetGroups 方法操作和截断字符串。这就减少了身份验证 cookie 中存储的字符串的长度。如果该字符串不会被截断,每个组的格式会显示,如下所示。
CN=...,...,DC=domain,DC=com
				
这可以创建一个非常长的字符串。cookie 的长度大于此字符串的长度是否浏览器可能不接受身份验证 cookie,您将被重定向到登录页。但是,如果要在多域环境中您可能不得不保留域名称使用的组名,因为在不同的域的组可以有相同的组名。您必须将保持到一个组有别于另一个域名。

大多数浏览器都支持多达 4096 字节的 cookie。如果该字符串可能会有可能超过 cookie 的长度,您可能希望在 ASP.NET 缓存对象或数据库中存储组信息。或者,您可能希望加密组信息并将此信息存储在隐藏的窗体字段。

编写 Global.asax 代码

在 Global.asax 文件中的代码提供了 Application_AuthenticateRequest 事件处理程序。此事件处理程序从 Context.Request.Cookies 集合中检索身份验证 cookie,对该的 cookie 进行解密并检索 FormsAuthenticationTicket.UserData 属性中将存储组的列表。在组将显示在管道分隔 Logon.aspx 页中创建的列表中。

代码分析该字符串在字符串数组创建 GenericPrincipal 对象中。在 GenericPrincipal 对象创建之后,该对象位于 HttpContext.User 属性中。
  1. 在解决方案资源管理器中,用鼠标右键单击 Global.asax,然后单击 查看代码
  2. 代码的-隐藏 Global.asax.cs 文件顶部添加下面的代码:
    using System.Web.Security;
    using System.Security.Principal;
    					
  3. 下面的代码替换为 Application_AuthenticateRequest 为现有的空事件处理程序
    void Application_AuthenticateRequest(Object sender, EventArgs e)
    {
      String cookieName = FormsAuthentication.FormsCookieName;
      HttpCookie authCookie = Context.Request.Cookies[cookieName];
    
      if(null == authCookie)
      {//There is no authentication cookie.
        return;
      }	
    		
      FormsAuthenticationTicket authTicket = null;
    	
      try
      {
        authTicket = FormsAuthentication.Decrypt(authCookie.Value);
      }
      catch(Exception ex)
      {
        //Write the exception to the Event Log.
        return;
      }
    	
      if(null == authTicket)
      {//Cookie failed to decrypt.
        return;		
      }		
    	
      //When the ticket was created, the UserData property was assigned a
      //pipe-delimited string of group names.
      String[] groups = authTicket.UserData.Split(new char[]{'|'});
    
      //Create an Identity.
      GenericIdentity id = new GenericIdentity(authTicket.Name, "LdapAuthentication");
    	
      //This principal flows throughout the request.
      GenericPrincipal principal = new GenericPrincipal(id, groups);
    
      Context.User = principal;
    	
    }
    					

修改 Web.config 文件

在这一节中,您配置在 <forms>,该 <authentication>,并在 <authorization> Web.config 文件中的元素。使用这些的更改只有已通过身份验证的用户可以访问该的应用程序和未经身份验证的请求重定向到 Logon.aspx 页。您可以修改此配置为允许只有某些用户和组访问应用程序。

在 Web.config 文件中的现有代码替换下面的代码。
<?xml version="1.0" encoding="utf-8" ?>
<configuration>    
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="logon.aspx" name="adAuthCookie" timeout="10" path="/" >
      </forms>
    </authentication>	
    <authorization>	
      <deny users="?" />
      <allow users="*" />
    </authorization>	
    <identity impersonate="true" />
  </system.web>
</configuration>
				
注意到在 <identity impersonate="true"/> 配置元素。这会使 ASP.NET 可以模拟该帐户被配置为匿名帐户从 Microsoft Internet Information Services (IIS)。由于这种配置而导致的对此应用程序的所有请求已配置的帐户的安全上下文下都运行。用户提供了对在活动目录进行身份验证的凭据,但访问 Active Directory 帐户是配置的帐户。有关详细的信息,请参阅 References 一节。

将 IIS 配置为匿名身份验证

若要将 IIS 配置为匿名身份验证,请按照下列步骤操作:
  1. 在 IIS 中,展开计算机节点,为您的服务器,展开 网站、 展开 默认网站FormsAuthAd,用鼠标右键单击,然后单击 属性
  2. 单击 目录安全性选项卡,然后单击 匿名访问和验证控件 下的 编辑
  3. 请为应用程序的匿名帐户具有活动目录的权限的帐户。
  4. 单击以清除允许 IIS 到控制密码复选框。
  5. 在身份验证的访问部分取消选中集成 Windows 身份验证复选框。
  6. 单击确定。
  7. 单击应用
默认 IUSR_ computername 的帐户不具有活动目录的权限。

创建 Logon.aspx 页

请按照下列步骤创建新 ASP.NET Web 窗体名为 Logon.aspx 操作:
  1. 在解决方案资源管理器中,用鼠标右键单击该项目节点,指向 添加,然后单击 添加 Web 窗体
  2. 名称 框中键入 Logon.aspx,然后单击 打开
  3. 在解决方案资源管理器中,用鼠标右键单击 Logon.aspx,然后单击 视图设计器
  4. 单击在设计器中的 HTML 选项卡。
  5. Replace the existing code with the following code.
    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="FormsAuth" %>
    <html>
      <body>	
        <form id="Login" method="post" runat="server">
          <asp:Label ID="Label1" Runat=server >Domain:</asp:Label>
          <asp:TextBox ID="txtDomain" Runat=server ></asp:TextBox><br>    
          <asp:Label ID="Label2" Runat=server >Username:</asp:Label>
          <asp:TextBox ID=txtUsername Runat=server ></asp:TextBox><br>
          <asp:Label ID="Label3" Runat=server >Password:</asp:Label>
          <asp:TextBox ID="txtPassword" Runat=server TextMode=Password></asp:TextBox><br>
          <asp:Button ID="btnLogin" Runat=server Text="Login" OnClick="Login_Click"></asp:Button><br>
          <asp:Label ID="errorLabel" Runat=server ForeColor=#ff3300></asp:Label><br>
          <asp:CheckBox ID=chkPersist Runat=server Text="Persist Cookie" />
        </form>	
      </body>
    </html>
    <script runat=server>
    void Login_Click(Object sender, EventArgs e)
    {
      String adPath = "LDAP://corp.com"; //Fully-qualified Domain Name
      LdapAuthentication adAuth = new LdapAuthentication(adPath);
      try
      {
        if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text))
        {
          String groups = adAuth.GetGroups();
    
          //Create the ticket, and add the groups.
          bool isCookiePersistent = chkPersist.Checked;
          FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,  txtUsername.Text,
    	DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups);
    	
          //Encrypt the ticket.
          String encryptedTicket = FormsAuthentication.Encrypt(authTicket);
    		
          //Create a cookie, and then add the encrypted ticket to the cookie as data.
          HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
    
          if(true == isCookiePersistent)
    	authCookie.Expires = authTicket.Expiration;
    				
          //Add the cookie to the outgoing cookies collection.
          Response.Cookies.Add(authCookie);		
    
          //You can redirect now.
          Response.Redirect(FormsAuthentication.GetRedirectUrl(txtUsername.Text, false));
        }
        else
        {
          errorLabel.Text = "Authentication did not succeed. Check user name and password.";
        }
      }
      catch(Exception ex)
      {
        errorLabel.Text = "Error authenticating. " + ex.Message;
      }
    }
    </script>
  6. 在修改路径 Logon.aspx 页,使其指向您 LDAP 目录服务器。
Logon.aspx 页是从用户和调用方法的信息收集 LdapAuthentication 类上的页。代码对用户进行身份验证,并获取组的列表后,代码创建一个 FormsAuthenticationTicket 对象、 加密票证、 加密的票证向 cookie,将添加到 HttpResponse.Cookies 集合中,cookie,然后将请求重定向到最初请求的 URL。

修改 WebForm1.aspx 页

WebForm1.aspx 页是最初请求的页。 当用户请求此页时,将请求重定向到该 Logon.aspx 页。请求进行身份验证之后,该请求会被重定向到 WebForm1.aspx 页。
  1. 在解决方案资源管理器中,用鼠标右键单击 WebForm1.aspx,然后单击 视图设计器
  2. 单击在设计器中的 HTML 选项卡。
  3. 将现有代码替换下面 code.
    <%@ Page language="c#" AutoEventWireup="true" %>
    <%@ Import Namespace="System.Security.Principal" %>
    <html>
      <body>	
        <form id="Form1" method="post" runat="server">
          <asp:Label ID="lblName" Runat=server /><br>
          <asp:Label ID="lblAuthType" Runat=server />
        </form>	
      </body>
    </html>
    <script runat=server>
    void Page_Load(Object sender, EventArgs e)
    {
      lblName.Text = "Hello " + Context.User.Identity.Name + ".";
      lblAuthType.Text = "You were authenticated using " +   Context.User.Identity.AuthenticationType + ".";
    }
    </script>
    					
  4. 保存所有的文件,然后编译该项目。
  5. 请求 WebForm1.aspx 页。请注意您将被重定向到 Logon.aspx。
  6. 键入登录凭据,然后单击 提交。当您将被重定向到 WebForm1.aspx 时,请注意,您的用户名出现和 $ LdapAuthentication 是身份验证将类型为 Context.User.AuthenticationType 属性。
注意Microsoft 建议使用安全套接字层 (SSL) 加密时使用 Forms 身份验证。这是因为基于身份验证 cookie 标识用户,此应用程序上的 SSL 加密防止任何人危及安全的身份验证 cookie 和正在传输的任何其他有价值的信息。

参考

有关详细的信息请单击下面的文章编号,以查看 Microsoft 知识库中相应的文章:
306590ASP.NET 安全性概述
317012在 ASP.NET 中的过程和请求身份
311495如何通过使用 Visual C#.net 在 ASP.NET 应用程序中实现基于窗体的身份验证与基于角色的安全性
313091如何创建通过使用 Visual Basic.net 在 Forms 身份验证中使用的键
313116窗体身份验证请求不被定向到 loginUrl 页

属性

文章编号: 316748 - 最后修改: 2007年10月16日 - 修订: 5.4
这篇文章中的信息适用于:
  • Microsoft Visual C# .NET 2003 标准版
  • Microsoft Visual C# .NET 2002 标准版
  • Microsoft ASP.NET 1.1
  • Microsoft ASP.NET 1.0
关键字:?
kbmt kbconfig kbcookie kbhowtomaster kbsecurity kbwebforms KB316748 KbMtzh
机器翻译
注意:这篇文章是由无人工介入的微软自动的机器翻译软件翻译完成。微软很高兴能同时提供给您由人工翻译的和由机器翻译的文章, 以使您能使用您的语言访问所有的知识库文章。然而由机器翻译的文章并不总是完美的。它可能存在词汇,语法或文法的问题,就像是一个外国人在说中文时总是可能犯这样的错误。虽然我们经常升级机器翻译软件以提高翻译质量,但是我们不保证机器翻译的正确度,也不对由于内容的误译或者客户对它的错误使用所引起的任何直接的, 或间接的可能的问题负责。
点击这里察看该文章的英文版: 316748
Microsoft和/或其各供应商对于为任何目的而在本服务器上发布的文件及有关图形所含信息的适用性,不作任何声明。 所有该等文件及有关图形均"依样"提供,而不带任何性质的保证。Microsoft和/或其各供应商特此声明,对所有与该等信息有关的保证和条件不负任何责任,该等保证和条件包括关于适销性、符合特定用途、所有权和非侵权的所有默示保证和条件。在任何情况下,在由于使用或运行本服务器上的信息所引起的或与该等使用或运行有关的诉讼中,Microsoft和/或其各供应商就因丧失使用、数据或利润所导致的任何特别的、间接的、衍生性的损害或任何因使用而丧失所导致的之损害、数据或利润不负任何责任。

提供反馈

 

Contact us for more help

Contact us for more help
Connect with Answer Desk for expert help.
Get more support from smallbusiness.support.microsoft.com