如何使用表單驗證及 Visual Basic .NET 通過 Active Directory 驗證

文章翻譯 文章翻譯
文章編號: 326340 - 檢視此文章適用的產品。
全部展開 | 全部摺疊

在此頁中

結論

本文將逐步告訴您,ASP.NET 如何利用「輕量型目錄存取協定」(LDAP),使用表單驗證以允許使用者通過 Active Directory 驗證。

使用者在經過驗證及重新導向之後,您可以使用 Global.asax 檔的 Application_AuthenticateRequest 方法,儲存流經整個要求之 HttpContext.User 屬性中的 GenericPrincipal 物件。

回到頁首

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

依照下列步驟,在 Visual Basic .NET 中建立名為 FormsAuthAd 的新 ASP.NET Web 應用程式:
  1. 啟動 Microsoft Visual Studio .NET。
  2. [檔案] 功能表上,指向 [新增],然後按一下 [專案]
  3. 按一下 [專案類型] 底下的 [Visual Basic 專案],再按一下 [範本] 底下的 [ASP.NET Web 應用程式]
  4. [位置] 方塊中,鍵入 http://<servername>/FormsAuthAd (如果使用本機伺服器則以 http://localhost 取代,即 http://localhost/FormsAuthAd),再按一下 [確定]
  5. 用滑鼠右鍵按一下 [方案總管] 中的 [參考] 節點,再按一下 [加入參考]
  6. [加入參考] 對話方塊的 [.NET] 索引標籤上,按一下 [System.DirectoryServices.dll],然後按一下 [選取],再按一下 [確定]
回到頁首

撰寫驗證代碼

依照下列步驟,建立名為 LdapAuthentication.vb 的新類別檔案:
  1. 在 [方案總管] 中,用滑鼠右鍵按一下專案節點,指向 [加入],然後按一下 [加入新項目]
  2. 按一下 [範本] 底下的 [類別]
  3. [名稱] 方塊中鍵入 LdapAuthentication.vb,再按一下 [開啟]
  4. 以下列程式碼取代 LdapAuthentication.vb 檔中的現有程式碼:
    Imports System
    Imports System.Text
    Imports System.Collections
    Imports System.DirectoryServices
    
    Namespace FormsAuth
        Public Class LdapAuthentication
    
            Dim _path As String
            Dim _filterAttribute As String
    
            Public Sub New(ByVal path As String)
                _path = path
            End Sub
    
            Public Function IsAuthenticated(ByVal domain As String, ByVal username As String, ByVal pwd As String) As Boolean
    
                Dim domainAndUsername As String = domain & "\" & username
                Dim entry As DirectoryEntry = New DirectoryEntry(_path, domainAndUsername, pwd)
    
                Try
                    'Bind to the native AdsObject to force authentication.			
                    Dim obj As Object = entry.NativeObject
                    Dim search As DirectorySearcher = New DirectorySearcher(entry)
    
                    search.Filter = "(SAMAccountName=" & username & ")"
                    search.PropertiesToLoad.Add("cn")
                    Dim result As SearchResult = search.FindOne()
    
                    If (result Is Nothing) Then
                        Return False
                    End If
    
                    'Update the new path to the user in the directory.
                    _path = result.Path
                    _filterAttribute = CType(result.Properties("cn")(0), String)
    
                Catch ex As Exception
                    Throw New Exception("Error authenticating user. " & ex.Message)
                End Try
    
                Return True
            End Function
    
            Public Function GetGroups() As String
                Dim search As DirectorySearcher = New DirectorySearcher(_path)
                search.Filter = "(cn=" & _filterAttribute & ")"
                search.PropertiesToLoad.Add("memberOf")
                Dim groupNames As StringBuilder = New StringBuilder()
    
                Try
                    Dim result As SearchResult = search.FindOne()
                    Dim propertyCount As Integer = result.Properties("memberOf").Count
    
                    Dim dn As String
                    Dim equalsIndex, commaIndex
    
                    Dim propertyCounter As Integer
    
                    For propertyCounter = 0 To propertyCount - 1
                        dn = CType(result.Properties("memberOf")(propertyCounter), String)
    
                        equalsIndex = dn.IndexOf("=", 1)
                        commaIndex = dn.IndexOf(",", 1)
                        If (equalsIndex = -1) Then
                            Return Nothing
                        End If
    
                        groupNames.Append(dn.Substring((equalsIndex + 1), (commaIndex - equalsIndex) - 1))
                        groupNames.Append("|")
                    Next
    
                Catch ex As Exception
                    Throw New Exception("Error obtaining group names. " & ex.Message)
                End Try
    
                Return groupNames.ToString()
            End Function
        End Class
    End Namespace
    
    
    					

程式碼說明

驗證代碼會接受網域、使用者名稱、密碼,以及到 Active Directory 中樹狀目錄的路徑。此程式碼會使用 LDAP 目錄提供者。
使用者驗證
Logon.aspx 網頁中的程式碼會呼叫 LdapAuthentication.IsAuthenticated 方法,並通過向使用者收集的憑證。然後,會使用到樹狀目錄的路徑、使用者名稱及密碼來建立 DirectoryEntry 物件。使用者名稱的格式必須是 domain\username。DirectoryEntry 物件接著會取得 NativeObject 屬性,以嘗試強制 AdsObject 繫結。如果成功,則會建立 DirectorySearcher 物件並於 SAMAccountName 上進行篩選,以取得使用者的 CN 屬性。在驗證過使用者之後,IsAuthenticated 方法會傳回 true

注意當您使用 LDAP 繫結至 Active Directory 相關物件時,會使用 TCP 通訊埠。增加含 System.DirectoryServices 命名空間之 LDAP 的使用,可能會用到所有可用的 TCP 通訊埠。您或許可以重新使用之前用來驗證使用者的連線,以減少 TCP 負載。
使用者群組
如果要取得使用者所屬群組的清單,此程式碼會呼叫 LdapAuthentication.GetGroups 方法。LdapAuthentication.GetGroups 方法會建立 DirectorySearcher 物件,並根據 memberOf 屬性進行篩選,以取得使用者所屬之安全性及通訊群組的清單。這個方法會傳回由 | 符號分隔的群組清單。

請注意,LdapAuthentication.GetGroups 方法會處理並截斷字串。這會減少驗證 Cookie 中所儲存之字串的長度。如果字串未經截斷,每個群組的格式會顯示如下:
CN=...,...,DC=domain,DC=com
				
這可建立非常長的字串。如果這個字串的長度大於 Cookie 的長度,則無法建立驗證 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.vb 檔後的程式碼頂端加入下列程式碼:
    Imports System.Web.Security
    Imports System.Security.Principal
    					
  3. 使用下列程式碼取代 Application_AuthenticateRequest 的現有空白事件處理常式:
    Sub Application_AuthenticateRequest(ByVal sender As Object, ByVal e As EventArgs)
            ' Fires upon attempting to authenticate the use
            Dim cookieName As String = FormsAuthentication.FormsCookieName
            Dim authCookie As HttpCookie = Context.Request.Cookies(cookieName)
    
            If (authCookie Is Nothing) Then
                'There is no authentication cookie.
                Return
            End If
    
            Dim authTicket As FormsAuthenticationTicket = Nothing
    
            Try
                authTicket = FormsAuthentication.Decrypt(authCookie.Value)
            Catch ex As Exception
                'Write the exception to the Event Log.
                Return
            End Try
    
            If (authTicket Is Nothing) Then
                'Cookie failed to decrypt.
                Return
            End If
    
            'When the ticket was created, the UserData property was assigned a
            'pipe-delimited string of group names.
            Dim groups As String() = authTicket.UserData.Split(New Char() {"|"})
    
            'Create an Identity.
            Dim id As GenericIdentity = New GenericIdentity(authTicket.Name, "LdapAuthentication")
    
            'This principal flows throughout the request.
            Dim principal As GenericPrincipal = New GenericPrincipal(id, groups)
    
            Context.User = principal
    
        End Sub
    					
回到頁首

修改 Web.config 檔

在本節中,您將設定 Web.config 檔中的 formsauthenticationauthorization 元素。進行這些變更之後,只有通過驗證的使用者可以存取應用程式,而未經驗證的要求會被重新導向到 Logon.aspx 網頁。您可以修改這個設定,只容許某些使用者和群組可以存取該應用程式。

以下列程式碼取代 Web.config 檔中的現有程式碼:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>    
  <system.web>
    <authentication mode="Forms">
      <forms loginUrl="logon.aspx" name="adAuthCookie" timeout="60" 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 驗證,但存取 Active Directory 的帳戶是所設定的帳戶。如需詳細資訊,請參閱<參考>一節。

回到頁首

設定 IIS 使用匿名驗證

如果要設定 IIS 使用匿名驗證,請依照下列步驟執行:
  1. 在 Internet Information Services (IIS) 管理主控台中,用滑鼠右鍵按一下 FormsAuthAd 的 [虛擬目錄] 節點。
  2. 按一下 [內容],然後按一下 [目錄安全性] 索引標籤。
  3. 按一下 [匿名存取及驗證控制] 下的 [編輯]
  4. 選取 [匿名存取] 核取方塊。
  5. 將應用程式的匿名帳戶設為具有 Active Directory 權限的帳戶。
  6. 按一下以清除 [允許 IIS 來控制密碼] 核取方塊。
預設的 IUSR_computername 帳戶沒有 Active Directory 的權限。

回到頁首

建立 Logon.aspx 網頁

依照下列步驟,建立名為 Logon.aspx 的新 ASP.NET Web Form:
  1. 在 [方案總管] 中,用滑鼠右鍵按一下專案節點,指向 [加入],然後按一下 [加入 Web Form]
  2. [名稱] 方塊中鍵入 Logon.aspx,再按一下 [開啟]
  3. 在 [方案總管] 中,用滑鼠右鍵按一下 Logon.aspx,然後按一下 [檢視設計工具]
  4. 按一下 [設計工具] 中的 [HTML] 索引標籤。
  5. 以下列程式碼取代現有的程式碼:
    <%@ Page language="vb" AutoEventWireup="true" %>
    <%@ Import Namespace="FormsAuthAd.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">
    sub Login_Click(sender as object,e as EventArgs)
      Dim adPath as String = "LDAP://DC=..,DC=.." 'Path to your LDAP directory server
      Dim adAuth as LdapAuthentication = new LdapAuthentication(adPath)
      try
        if(true = adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text)) then
          Dim groups as string = adAuth.GetGroups()
    
          'Create the ticket, and add the groups.
          Dim isCookiePersistent as boolean = chkPersist.Checked
          Dim authTicket as FormsAuthenticationTicket = new FormsAuthenticationTicket(1, _
               txtUsername.Text,DateTime.Now, DateTime.Now.AddMinutes(60), isCookiePersistent, groups)
    	
          'Encrypt the ticket.
          Dim encryptedTicket as String = FormsAuthentication.Encrypt(authTicket)
    		
          'Create a cookie, and then add the encrypted ticket to the cookie as data.
          Dim authCookie as HttpCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket)
    
          if(isCookiePersistent = true) then
    		authCookie.Expires = authTicket.Expiration
          end if				
          '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."
        end if
     
      catch ex as Exception
        errorLabel.Text = "Error authenticating. " & ex.Message
      end try
    end sub
    </script>
    					
  6. 修改 Logon.aspx 網頁中的路徑,指向您的 LDAP 目錄伺服器。
Logon.aspx 網頁是用來收集來自使用者的資訊,並呼叫 LdapAuthentication 類別方法的網頁。在程式碼驗證使用者並取得群組清單後,即會按這個順序進行下列動作:
  • 建立 FormsAuthenticationTicket 物件;
  • 將票證加密;
  • 將加密的票證加入 Cookie 中;
  • 將 Cookie 加入 HttpResponse.Cookies 集合;
  • 將要求重新導向到原來要求的 URL。
回到頁首

修改 WebForm1.aspx 網頁

WebForm1.aspx 網頁是原來要求的網頁。當使用者要求這個網頁時,會將要求重新導向到 Logon.aspx 網頁。驗證要求之後,會將要求重新導向到 WebForm1.aspx 網頁。
  1. 在 [方案總管] 中,用滑鼠右鍵按一下 [WebForm1.aspx],然後按一下 [檢視設計工具]
  2. 按一下 [設計工具] 中的 [HTML] 索引標籤。
  3. 以下列程式碼取代現有的程式碼:
    <%@ Page language="vb" 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">
    sub Page_Load(sender as object, e as EventArgs)
      lblName.Text = "Hello " + Context.User.Identity.Name & "."
      lblAuthType.Text = "You were authenticated using " &   Context.User.Identity.AuthenticationType & "."
    end sub
    </script>
    					
  4. 儲存所有檔案,然後編譯專案。
  5. 要求 WebForm1.aspx 網頁。請注意,您會被重新導向到 Logon.aspx。
  6. 輸入登入認證,然後按一下 [送出]。當您被重新導向到 WebForm1.aspx 時,請注意,您的使用者名稱會出現,且 LdapAuthenticationContext.User.Identity.AuthenticationType 屬性的驗證類型。
注意Microsoft 建議您在使用表單驗證時使用 Secure Sockets Layer (SSL) 加密。這是因為使用者是根據驗證 Cookie 加以識別,且這個應用程式的 SSL 加密可防止任何人洩漏驗證 Cookie 及任何其他正在傳送的寶貴資訊。

回到頁首

?考

如需詳細資訊,請按一下下面的文件編號,檢視「Microsoft 知識庫」中的文件:
306590 INFO:ASP.NET 安全性概觀
317012 ASP.NET 中的處理序及要求識別
306238 How To Implement Role-Based Security with Forms-Based Authentication in Your ASP.NET Application by Using Visual Basic .NET
313091 How to create keys by using Visual Basic .NET for use in Forms authentication
313116 PRB: Forms Authentication Requests Are Not Directed to loginUrl Page
回到頁首

屬性

文章編號: 326340 - 上次校閱: 2006年9月1日 - 版次: 4.3
這篇文章中的資訊適用於:
  • Microsoft ASP.NET 1.0
  • Microsoft Visual Basic .NET 2002 Standard Edition
  • Microsoft ASP.NET 1.1
  • Microsoft Visual Basic .NET 2003 Standard Edition
關鍵字:?
kbconfig kbcookie kbhowtomaster kbsecurity kbwebforms KB326340
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