Active Directory-Domänendiensteauthentifizierung von ASP.NET
In diesem Thema wird veranschaulicht, wie eine ASP.NET-Anwendung mithilfe der Formularauthentifizierung die Authentifizierung von Benutzern bei den Active Directory-Domänendiensten über LDAP (Lightweight Directory Access Protocol) ermöglicht wird. Nach der Authentifizierung und Umleitung des Benutzers können Sie die Application_AuthenticateRequest-Methode der Datei Global.asax verwenden, um ein GenericPrincipal-Objekt in der HttpContext.User-Eigenschaft zu speichern, das in der ganzen Anforderung verwendet wird.
So erstellen Sie eine neue ASP.NET-Webanwendung
Starten Sie Microsoft Visual Studio :NET.
Zeigen Sie im Menü Datei auf Neu, und klicken Sie dann auf Projekt.
Klicken Sie unter Projekttypen auf Visual C#-Projekte. Klicken Sie anschließend unter Vorlagen auf ASP.NET-Webanwendung.
Geben Sie im Feld Name die Zeichenfolge FormsAuthAd ein.
Übernehmen Sie im Feld Server die Standardeinstellung https://localhost, wenn der lokale Server verwendet wird. Fügen Sie andernfalls den Pfad zum Server ein. Klicken Sie auf OK.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Knoten Verweise, und klicken Sie dann auf Verweis hinzufügen.
Klicken Sie im Dialogfeld Verweis hinzufügen auf der Registerkarte .NET auf System.DirectoryServices.dll. Klicken Sie anschließend auf Auswählen und dann auf OK.
So fügen Sie System.DirectoryServices-Authentifizierungscode hinzu
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektknoten, klicken Sie auf Hinzufügen und anschließend auf Neues Element hinzufügen.
Klicken Sie unter Vorlagen auf Klasse.
Geben Sie im Feld Name den Namen LdapAuthentication.cs ein, und klicken Sie dann auf Öffnen.
Ersetzen Sie den in der Datei LdapAuthentication.cs vorhandenen Code durch folgenden Code:
using System; using System.Text; using System.Collections; using System.Web.Security; using System.Security.Principal; 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(); } } }
In der obigen Prozedur übernimmt der Authentifizierungscode eine Domäne, einen Benutzernamen, ein Kennwort und einen Pfad zur Struktur in den Active Directory-Domänendiensten. In diesem Code wird der LDAP-Verzeichnisanbieter verwendet. Der Code in der Seite Logon.aspx ruft die LdapAuthentication.IsAuthenticated-Methode auf und übergibt die vom Benutzer eingegebenen Anmeldeinformationen. Danach wird ein DirectoryEntry-Objekt mit dem Pfad zur Verzeichnisstruktur, dem Benutzernamen und dem Kennwort erstellt. Der Benutzername muss das Format "Domäne\Benutzername" aufweisen.
Das DirectoryEntry-Objekt versucht dann eine Bindung von AdsObject zu erzwingen, indem die NativeObject-Eigenschaft abgerufen wird. Bei einer erfolgreichen Bindung wird das CN-Attribut des Benutzers abgerufen, indem ein DirectorySearcher-Objekt erstellt und eine Filterung anhand sAMAccountName ausgeführt wird. Weitere Informationen zu sAMAccountName im Schema der Active Directory-Domänendienste finden Sie unter "sAMAccountName" bzw. "SAM-Account-Name attribute" in der MSDN Library (möglicherweise in englischer Sprache). Nach der Authentifizierung des Benutzers gibt die IsAuthenticated-Methode true zurück. Um eine Liste der Gruppen abzurufen, zu denen der Benutzer gehört, wird im Code die LdapAuthentication.GetGroups-Methode aufgerufen. Die LdapAuthentication.GetGroups-Methode ruft eine Liste der Sicherheits- und Verteilergruppen ab, zu denen der Benutzer gehört, indem ein DirectorySearcher-Objekt erstellt und eine Filterung anhand des memberOf-Attributs ausgeführt wird. Weitere Informationen zu memberOf im Schema der Active Directory-Domänendienste finden Sie unter "memberOf" oder "Is-Member-Of-DL attribute" in der MSDN Library (möglicherweise in englischer Sprache). Diese Methode gibt eine durch Pipe-Zeichen (|) getrennte Liste der Gruppen zurück. Beachten Sie, dass die LdapAuthentication.GetGroups-Methode Zeichenfolgen bearbeitet und kürzt. Dadurch wird die Länge der Zeichenfolge verringert, die im Authentifizierungscookie gespeichert wird. Bei einer ungekürzten Zeichenfolge sieht das Format der einzelnen Gruppen wie folgt aus:
CN=...,...,DC=domain,DC=com
Die LdapAuthentication.GetGroups-Methode kann eine sehr lange Zeichenfolge zurückgeben. Wenn die Länge dieser Zeichenfolge größer ist als die Länge des Cookies, kann das Authentifizierungscookie nicht erstellt werden. Wenn diese Zeichenfolge möglicherweise die Länge des Cookies überschreiten kann, sollten Sie die Gruppeninformationen im ASP.NET Cache-Objekt oder in einer Datenbank speichern. Alternativ können Sie die Gruppeninformationen verschlüsseln und die Informationen in einem ausgeblendeten Formularfeld speichern.
Der Code in der Datei Global.asax stellt einen Application_AuthenticateRequest-Ereignishandler bereit. Dieser Ereignishandler ruft das Authentifizierungscookie aus der Context.Request.Cookies-Auflistung ab, entschlüsselt das Cookie und ruft die Liste der Gruppen ab, die in der FormsAuthenticationTicket.UserData-Eigenschaft gespeichert wird. Die Gruppen befinden sich in einer Liste mit dem Pipe-Zeichen als Trennzeichen, die in der Seite Logon.aspx erstellt wird. Der Code zerlegt die Zeichenfolge in ein Zeichenfolgearray, um ein GenericPrincipal-Objekt zu erstellen. Nachdem das GenericPrincipal-Objekt erstellt wurde, wird dieses Objekt in die HttpContext.User-Eigenschaft eingefügt.
So schreiben Sie den Global.asax-Code
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Global.asax und dann auf Code anzeigen.
Fügen Sie am Anfang von Code-Behind für die Datei Global.asax.cs den folgenden Code hinzu:
using System.Web.Security; using System.Security.Principal;
Ersetzen Sie den vorhandenen leeren Ereignishandler für Application_AuthenticateRequest durch den folgenden Code:
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; }
In diesem Abschnitt werden die Elemente <forms>, <authentication> und <authorization> in der Datei Web.config konfiguriert. Durch diese Änderungen können nur authentifizierte Benutzer auf die Anwendung zugreifen. Nicht authentifizierte Anforderungen werden auf eine Logon.aspx-Seite umgeleitet. Sie können diese Konfiguration ändern, damit nur bestimmte Benutzer und Gruppen auf die Anwendung zugreifen können.
So ändern Sie die Web.config-Datei
Öffnen Sie Web.config in Editor.
Ersetzen Sie den vorhandenen Code durch folgenden Code:
<?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>
Beachten Sie das folgende Konfigurationselement:
<identity impersonate="true"/>
Dieses Element bewirkt, dass ASP.NET einen Identitätswechsel für das Konto ausführt, das in den Microsoft Internetinformationsdiensten (IIS) als anonymes Konto konfiguriert ist. Aufgrund dieser Konfiguration werden alle Anforderungen an diese Anwendung unter dem Sicherheitskontext des konfigurierten Kontos ausgeführt. Der Benutzer gibt die Anmeldeinformationen für die Authentifizierung bei den Active Directory-Domänendiensten an. Beim Konto, das auf die Active Directory-Domänendienste zugreift, handelt es sich aber um das konfigurierte Konto.
So konfigurieren Sie IIS für die anonyme Authentifizierung
Klicken Sie im Internetdienste-Manager (in Verwaltung) oder im MMC-Snap-In für IIS mit der rechten Maustaste auf die Website, für die Sie die Authentifizierung konfigurieren möchten, und klicken Sie dann auf Eigenschaften.
Klicken Sie auf die Registerkarte Verzeichnissicherheit und dann unter Authentifizierung und Zugriffsteuerung auf Bearbeiten.
Aktivieren Sie das Kontrollkästchen Anonyme Authentifizierung (in Windows Server 2003 mit Anonymen Zugriff aktivieren beschriftet).
Legen Sie das anonyme Konto für die Anwendung als ein Konto fest, das über Berechtigung für die Active Directory-Domänendienste verfügt.
Deaktivieren Sie das Kontrollkästchen Kennwortkontrolle durch IIS zulassen (sofern vorhanden). Das Standardkonto IUSR*_<Computername>* verfügt über keine Berechtigungen für die Active Directory-Domänendienste.
So erstellen Sie die Logon.aspx-Seite
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf den Projektknoten, klicken Sie auf Hinzufügen und anschließend auf Web Form hinzufügen.
Geben Sie im Feld Name den Namen Logon.aspx ein, und klicken Sie dann auf Öffnen.
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf Logon.aspx, und wählen Sie Designer anzeigen aus.
Wählen Sie im Designer die Registerkarte HTML aus.
Ersetzen Sie den vorhandenen Code durch folgenden 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://" + txtDomain.Text; LdapAuthentication adAuth = new LdapAuthentication(adPath); try { if(true == adAuth.IsAuthenticated(txtDomain.Text, txtUsername.Text, txtPassword.Text)) { string groups = adAuth.GetGroups(txtDomain.Text, txtUsername.Text, txtPassword.Text); //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>
Ändern Sie den Pfad in der Seite Logon.aspx so, dass er auf den entsprechenden LDAP-Verzeichnisserver verweist.
Die Seite Logon.aspx erfasst die Informationen vom Benutzer und ruft Methoden in der LdapAuthentication-Klasse auf. Nachdem der Code den Benutzer authentifiziert und eine Liste der Gruppen abgerufen hat, erstellt der Code ein FormsAuthenticationTicket-Objekt. Anschließend wird das Ticket verschlüsselt, das verschlüsselte Ticket zu einem Cookie hinzugefügt, das Cookie zur HttpResponse.Cookies-Auflistung hinzugefügt und die Anforderung an die ursprünglich angeforderte URL umgeleitet.
Bei der ursprünglich angeforderten Seite handelt es sich um die Seite WebForm1.aspx. Wenn der Benutzer diese Seite anfordert, wird die Anforderung an die Seite Logon.aspx umgeleitet. Nachdem die Anforderung authentifiziert wurde, wird die Anforderung an die Seite WebForm1.aspx umgeleitet.
So ändern Sie die WebForm1.aspx-Seite
Klicken Sie im Projektmappen-Explorer mit der rechten Maustaste auf WebForm1.aspx, und wählen Sie Designer anzeigen aus.
Wählen Sie im Designer die Registerkarte HTML aus.
Ersetzen Sie den vorhandenen Code durch folgenden 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>
Speichern Sie alle Dateien, und kompilieren Sie anschließend das Projekt.
Rufen Sie die Seite WebForm1.aspx auf. Sie werden dann an die Seite Logon.aspx umgeleitet.
Geben Sie die Anmeldeinformationen ein, und klicken Sie dann auf Submit. Beachten Sie, dass bei der Umleitung zu WebForm1.aspx Ihr Benutzername angezeigt wird und als Authentifizierungstyp für die Context.User.AuthenticationType-Eigenschaft LdapAuthentication verwendet wird.
Hinweis: |
---|
Es wird empfohlen, bei Verwendung der Formularauthentifizierung die SSL-Verschlüsselung (Secure Sockets Layer) zu verwenden, weil der Benutzer anhand des Authentifizierungscookies identifiziert wird. Die SSL-Verschlüsselung für diese Anwendung verhindert in diesem Fall, dass das Authentifizierungscookie und andere wertvolle Informationen, die übertragen werden, gefährdet werden. |
Siehe auch
Referenz
System.DirectoryServices
DirectoryEntry
DirectorySearcher
Konzepte
Weiterführende Themen zur Programmierung
Send comments about this topic to Microsoft.
Copyright © 2007 Microsoft Corporation. Alle Rechte vorbehalten.