如何使用表單驗證和 Visual C#.NET 對 Active Directory 進行驗證

文章翻譯 文章翻譯
文章編號: 316748 - 檢視此文章適用的產品。
本文參照下列 Microsoft.NET Framework 類別庫的命名空間:
  • System.Text
  • System.DirectoryServices
  • System.Security.Principal
  • System.Web.Security
全部展開 | 全部摺疊

在此頁中

結論

本文將逐步告訴您,如何將 ASP.NET 應用程式可以使用表單驗證來允許使用者使用輕量型目錄存取通訊協定 (LDAP) 來對 Active Directory 進行驗證。使用者已通過驗證並重新導向之後,可以使用的 Global.asax 檔 Application_AuthenticateRequest 方法 GenericPrincipal 物件儲存在整個要求流動 HttpContext.User 屬性中。

在 Visual C#.NET 中建立 ASP.NET Web 應用程式

請依照下列步驟建立新的 ASP.NET Web 應用程式,名為 FormsAuthAd Visual C#.NET 中:
  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 繫結。如果這成功藉由建立 DirectorySearcher 物件以及篩選 SAMAccountName 取得使用者 CN 屬性。使用者通過驗證後 IsAuthenticated 方法會傳回 true

若要取得使用者所屬的群組清單,這段程式碼會呼叫 LdapAuthentication.GetGroups 方法。LdapAuthentication.GetGroups 方法會取得使用者藉由建立 DirectorySearcher 物件以及篩選根據來 memberOf 屬性所屬的安全性和通訊群組的清單。這個方法會傳回以管道 (|) 分隔群組清單。

請注意 LdapAuthentication.GetGroups 方法操作,而且會截斷字串。這樣可以減少儲存在驗證 Cookie 中的字串的長度。如果不截斷字串,每個群組的格式出現,如下所示。
CN=...,...,DC=domain,DC=com
				
這樣可以建立非常長的字串。如果這個字串的長度大於 Cookie 的長度,瀏覽器可能不接受驗證的 Cookie,您將會被重新導向至登入頁面。不過,如果您是在多網域環境中,您可能必須保持網域名稱,與群組名稱,因為不同網域中的群組可以有相同的群組名稱。您必須保留網域名稱來區別的一個群組。

大多數的瀏覽器都支援 Cookie 4096 個位元組。如果這個字串有潛在可能會超過 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 「 網際網路資訊服務 (IIS) 的帳戶。此組態的結果對這個應用程式的所有要求設定帳戶的安全性內容下都執行。使用者提供認證來驗證對 Active Directory,但存取 Active Directory 的帳戶設定的帳戶。如需詳細資訊,請參閱 References 章節。

設定 IIS 以進行匿名驗證

如果要設定 IIS 以進行匿名驗證,請依照下列步驟執行:
  1. 在 IIS 中,展開您的伺服器的 [電腦] 節點,展開 [網站]、 展開 [預設網站FormsAuthAd,] 上按一下滑鼠右鍵,然後再按一下 [內容]。
  2. 按一下 [目錄安全性] 索引標籤,然後按一下 [[匿名存取及驗證控制] 下的 [編輯]。
  3. 請為應用程式的匿名帳戶具有 Active Directory 的權限的帳戶。
  4. 按一下以清除 [允許 IIS 到控制密碼] 核取方塊。
  5. 「 已驗證存取 」] 區段中取消核取 「 整合式 Windows 驗證 」] 核取方塊。
  6. 按一下 [確定]。
  7. 按一下 [套用]
預設 IUSR_ computername 帳戶並沒有 Active Directory 的權限。

建立 Logon.aspx 網頁

請依照下列步驟執行來建立新的 ASP.NET Web Form 名為 Logon.aspx:
  1. 在 [方案總管] 中以滑鼠右鍵按一下專案節點,並指向 [新增,然後按一下 [加入 Web Form
  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. 修改路徑來指向您的 LDAP 目錄伺服器 Logon.aspx 網頁中。
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) 加密,當您使用表單驗證。這是因為根據驗證的 Cookie 來識別使用者,這個應用程式上的 SSL 加密可防止任何人都互相驗證 Cookie 以及任何其他的寶貴資訊,傳輸。

?考

如需詳細資訊按一下 [下面的文件編號,檢視 「 Microsoft 知識庫 」 中 「 文件]:
306590ASP.NET 安全性概觀
317012在 ASP.NET 中的處理程序和要求識別
311495如何使用 Visual C#.NET,ASP.NET 應用程式中實作角色架構安全性與表單基礎的驗證
313091如何建立以用於表單驗證使用 Visual Basic.NET 的機碼
313116表單驗證要求不會導向至 loginUrl 頁面

屬性

文章編號: 316748 - 上次校閱: 2007年10月16日 - 版次: 5.4
這篇文章中的資訊適用於:
  • Microsoft Visual C# .NET 2003 標準版
  • Microsoft Visual C# .NET 2002 Standard Edition
  • Microsoft ASP.NET 1.1
  • Microsoft ASP.NET 1.0
關鍵字:?
kbmt kbconfig kbcookie kbhowtomaster kbsecurity kbwebforms KB316748 KbMtzh
機器翻譯
重要:本文是以 Microsoft 機器翻譯軟體翻譯而成,而非使用人工翻譯而成。Microsoft 同時提供使用者人工翻譯及機器翻譯兩個版本的文章,讓使用者可以依其使用語言使用知識庫中的所有文章。但是,機器翻譯的文章可能不盡完美。這些文章中也可能出現拼字、語意或文法上的錯誤,就像外國人在使用本國語言時可能發生的錯誤。Microsoft 不為內容的翻譯錯誤或客戶對該內容的使用所產生的任何錯誤或損害負責。Microsoft也同時將不斷地就機器翻譯軟體進行更新。
按一下這裡查看此文章的英文版本: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