Glengamoi (Forum) · AspHeute · .NET Heute (RSS-Suche) · AspxFiles (Wiki) · .NET Blogs

Formularbasierte Authentifizierung in fünf Minuten

Geschrieben von: Christoph Wille
Kategorie: ASP.NET

This printed page brought to you by AlphaSierraPapa

In Anlehnung an diverse Buchserien werde ich Ihnen heute zeigen, wie schnell man mit ASP.NET eine Website für registrierte User erstellen kann. Da mir nach den fünf Minuten noch Zeit übrig bleibt, gebe ich Ihnen noch eine fix und fertige Lösung für ein technisch sauberes und vor allem sicheres Loginformular mit auf den Weg.

ASP.NET ist in vielen Bereichen revolutionär, so auch bei der Authentifizierung und der Authorisierung. Um die Begriffe zu definieren: Authentifizierung ist die Überprüfung ob der User der ist, der er vorgibt zu sein, und Authorisierung ist der Vorgang der Überprüfung ob der authentifizierte User auf eine bestimmte Resource zugreifen darf. Beide - Authentifizierung und Authorisierung - können je nach Bedarf durch eigene Implementationen ausgetauscht werden. Wir beschäftigen uns heute mit der am Web üblichsten Methode der Authentifizierung: formularbasierte Logins.

In klassischem ASP hat man eine geschlossene Webapplikation nach folgendem Muster entwickelt:

Der Nachteil dieser Lösung ist klarerweise daß man alle ASP Dateien modifizieren muß. Mit ASP.NET ist das nicht mehr notwendig, wie ich Ihnen zeigen werde.

Die Implementation

Ich habe Ihnen versprochen, daß Sie innerhalb von fünf Minuten eine mit Forms-based Authentication gesicherte Webapplikation bekommen. Beginnen wir also, und zwar mit tatkräftiger Hilfe des ASP.NET Web Matrix Projekts. Wir benötigen zwei Dinge: eine web.config und ein passendes Loginformular. Beginnen wir damit, in einem neuen Verzeichnis namens basicformauth eine web.config anzulegen:

Der geübte Leser ahnt bereits, daß die Technik des heutigen Artikels wieder einmal "gewußt wo" lautet. Stimmt, das ASP.NET Web Matrix Projekt legt uns eine für formularbasierte Authentifizierung perfekt geeignete web.config an (Details zu web.config finden Sie im Artikel Web.Config 101)::

<?xml version="1.0" encoding="UTF-8" ?>

<configuration>

  <system.web>

    <authentication mode="Forms">
      <forms name=".ASPXAUTH" loginUrl="login.aspx" />
    </authentication>  
    
    <authorization>
      <deny users="?" /> 
    </authorization>

  </system.web>

</configuration>

Die springenden Punkte sind die authentication und authorization Nodes. Erstere legt die Art der Authentication (Forms) fest, zweitere sorgt dafür, daß anonymer Zugriff (?) auf unser Web nicht erlaubt ist, also Eintritt nur über das Loginformular gestattet ist. Dieses wird in der authentication Node definiert, und muß von "uns" angelegt werden:

Mit dieser Vorlage bekommen wir ein fix & fertiges Loginformular, das im Designer so aussieht:

Bevor wir uns den Code ansehen, müssen wir noch sicherstellen daß unsere web.config auch ihren Dienst verrichten kann. Da wir Authentifizierung verlangen, müssen wir das neu erstellte Verzeichnis zu einem Applikationsroot machen. Dies geschieht im ISM, Eigenschaften des Verzeichnisses, Applikation anlegen. Danach hat das Verzeichnis ein Paketsymbol vorangestellt:

Nun legen Sie sich eine Testdatei an, in meinem Fall ist das coolpage.aspx. Gehen Sie mit dem Webbrowser auf diese Seite, und voila, Sie landen auf der Loginseite! Auftrag ausgeführt, unsere Applikation ist nur mehr für berechtigte User zugänglich - aber halt, wer sind denn die Berechtigen?

Dazu sehen wir uns den Code der login.aspx an:

<%@ Page Language="C#" %>
<script runat="server">
    void LoginBtn_Click(Object sender, EventArgs e) {
    
        if (Page.IsValid) {
            if ((UserName.Text == "jdoe@somewhere.com") && (UserPass.Text == "password")) {
                FormsAuthentication.RedirectFromLoginPage(UserName.Text, true);
            }
            else {
                Msg.Text = "Invalid Credentials: Please try again";
            }
        }
    }
</script>

Ja, im Moment kann nur ein einzelner User einloggen, und der ist noch dazu fest verdrahtet. Damit kommen wir zu Teil 2 des Artikels: der technisch sauberen und vor allem sicheren Lösung für das Loginformular.

Formularbasierter Login mit Datenbank

In den meisten aller Fälle wird man die Benutzerkonten in einer Datenbank ablegen. Dafür möchte ich Ihnen heute eine "Best Practice" zur Verwendung in Ihren Applikationen mitgeben: technisch sauber, und vor allem sicher.

Als Datenbank habe ich eine einfache Accessdatenbank mit einer einzigen Tabelle gewählt, damit man später leicht auf andere Datenbankprodukte migrieren kann. Die Tabelle sieht so aus:

Den Datenbankconnectionstring speichere ich wie in Artikel Einstellungssache - Applikationsdaten in web.config gezeigt in der web.config, zusätzlich zu den bereits bestehenden Eintragungen:

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
  <system.web>

    <authentication mode="Forms">
      <forms name=".ASPXAUTH" loginUrl="login.aspx" />
    </authentication>  
    
    <authorization>
      <deny users="?" /> 
    </authorization>

    <!-- Bei Fehlern die nachfolgende Zeile von Kommentarzeichen "befreien"
         um die vollständige Fehlermeldung angezeigt zu bekommen. Auf "Live-Systemen"
         niemals debug="true" eingeschaltet lassen!!! -->

    <!-- <compilation debug="true"/> -->
  </system.web>

  <appSettings>
     <add key="LoginDb" value="PROVIDER=Microsoft.Jet.OLEDB.4.0;Data Source=f:\aspheute\login.mdb" />
  </appSettings>
</configuration>

Andere Connection Strings, zB für SQL Server können Sie im Artikel Datenbankzugriff mittels ADO.NET nachlesen. Die weitere Änderung betrifft unser Loginformular login.aspx. Dort müssen wir die Methode LoginBtn_Click deutlich umbauen:

    void LoginBtn_Click(Object sender, EventArgs e) 
    {
        if (Page.IsValid) 
        {
            // holen des Connection Strings aus den <appSettings>
            string strDbConnString = ConfigurationSettings.AppSettings["LoginDb"];
            
            // verbinden zur Datenbank
            OleDbConnection con = new OleDbConnection(strDbConnString);
            con.Open();
            
            // SQL Injection sicher nicht mit uns!
            OleDbCommand cmd = new OleDbCommand();
            cmd.CommandText = "SELECT COUNT(*) FROM login WHERE UPN=@ParamUpn AND Password=@ParamPwd";
            cmd.Parameters.Add("@ParamUpn", UserName.Text);
            cmd.Parameters.Add("@ParamPwd", UserPass.Text);
            cmd.Connection = con;
            
            // korrektes Auslesen des mit ExecuteScalar geholten Wertes
            int nUsersMatched = 0;
            object oResult = cmd.ExecuteScalar();
            if (oResult != null) nUsersMatched = (int)oResult;
			
            // Command & Connection so früh als möglich schließen
            cmd.Dispose();
            con.Close();
            
            if (0 != nUsersMatched) {
                FormsAuthentication.RedirectFromLoginPage(UserName.Text, true);
            }
            else {
                Msg.Text = "Invalid Credentials: Please try again";
            }
        }
    }

Mit dem Aufruf von ConfigurationSettings.AppSettings holen wir uns den Connection String aus web.config. Mit diesem Connection String bauen wir eine OleDbConnection auf. Danach gehen wir absolut auf Nummer sicher: anstatt den SQL String dynamisch zusammenzubauen, verwenden wir eine parametrisierte Abfrage. Mehr dazu können Sie im Artikel Verhinderung von SQL Injection Marke .NET nachlesen, beziehungsweise sich im Artikel SQL Injection über die Hintergründe informieren.

Die parametrisierte Abfrage liefert uns 0 wenn die Logindaten inkorrekt sind, beziehungsweise 1 wenn der User authentifiziert werden konnte. Das Auslesen des Rückgabewerts von ExecuteScalar sollte man übrigens immer so wie gezeigt machen, und ebenfalls sollten alle verwendeten Resourcen (OleDbCommand und OleDbConnection) so schnell als möglich freigegeben werden.

Abschließend ist die orginale if Bedingung getauscht, der Code in der if Verzweigung selbst ist unverändert. Damit hätten wir dieses Kochrezept für ein datenbankgestütztes Loginformular auch schon abgeschlossen. Wollen Sie SQL Server einsetzen, so machen Sie eine Replaceoperation auf OleDb und tauschen alle Matches gegen Sql aus!

Schlußbemerkung

Formularbasierte Authentifizierung ist mit ASP.NET kinderleicht und vor allem schnell implementiert. Die vorgestellte Datenbanklösung können Sie für Ihre Applikationen als Startpunkt nehmen, da von vorne bis hinten auf Sicherheit geachtet wurde.

This printed page brought to you by AlphaSierraPapa

Download des Codes

Klicken Sie hier, um den Download zu starten.
http://www.aspheute.com/code/20020705.zip

Verwandte Artikel

Das ASP.NET Web Matrix Projekt
http:/www.aspheute.com/artikel/20020618.htm
Datenbankzugriff mittels ADO.NET
http:/www.aspheute.com/artikel/20001102.htm
Datentypen in C#
http:/www.aspheute.com/artikel/20000726.htm
Einführung in ASP.NET Validation Controls (Teil 1)
http:/www.aspheute.com/artikel/20000911.htm
Einführung in ASP.NET Validation Controls (Teil 2)
http:/www.aspheute.com/artikel/20000913.htm
Einführung in ASP.NET Web Forms
http:/www.aspheute.com/artikel/20000808.htm
Einstellungssache - Applikationsdaten in web.config
http:/www.aspheute.com/artikel/20011122.htm
Einstieg in Visual Studio.NET - die erste Webanwendung mit Visual C#
http:/www.aspheute.com/artikel/20031010.htm
Eventbehandlung bei ASP.NET WebForms
http:/www.aspheute.com/artikel/20000922.htm
Exception Handling in C#
http:/www.aspheute.com/artikel/20000724.htm
Kontrollstatements in C#
http:/www.aspheute.com/artikel/20000714.htm
MS IE WebControls 101
http:/www.aspheute.com/artikel/20020801.htm
Performancemessungen in .NET
http:/www.aspheute.com/artikel/20011206.htm
Sichere Konvertierungen von Referenztypen
http:/www.aspheute.com/artikel/20001019.htm
SQL Injection
http:/www.aspheute.com/artikel/20011030.htm
Tracing in ASP.NET
http:/www.aspheute.com/artikel/20001006.htm
Vergleich von DataGrid, DataList und Repeater-Control - was verwende ich wann?
http:/www.aspheute.com/artikel/20040303.htm
Verhinderung von SQL Injection Marke .NET
http:/www.aspheute.com/artikel/20011203.htm
Web.Config 101
http:/www.aspheute.com/artikel/20010802.htm

 

©2000-2006 AspHeute.com
Alle Rechte vorbehalten. Der Inhalt dieser Seiten ist urheberrechtlich geschützt.
Eine Übernahme von Texten (auch nur auszugsweise) oder Graphiken bedarf unserer schriftlichen Zustimmung.