Benutzer und Berechtigungen ermitteln

Lies diesen Artikel und viele weitere mit einem kostenlosen, einwöchigen Testzugang.

In den Beiträgen „Benutzerverwaltung mit verschlüsselten Kennwörtern“ und „Berechtigungen per HTML verwalten“ haben wir die Voraussetzungen für eine Benutzerverwaltung geschaffen. Im vorliegenden Beitrag bauen wir darauf auf und legen ein Anmeldeformular an, mit dem der Benutzer sich an der Anwendung anmelden kann. Außerdem stellen wir die Funktion vor, mit der wir aus den Tabellen zur Verwaltung der Berechtigungen aufgrund des Benutzernamens die Berechtigung an einer bestimmten Tabelle ermitteln.

In den Beiträgen Benutzerverwaltung mit verschlüsselten Kennwörtern (www.access-im-unternehmen.de/1190) und Berechtigungen per HTML verwalten (www.access-im-unternehmen.de/1191) haben wir das Datenmodell und die Formulare zur Verwaltung unseres Berechtigungssystems vorbereitet.

Daraus ist das Datenmodell aus Bild 1 entstanden, auf dem dieser Beitrag aufbaut. Für die Anmeldung an der Anwendung benötigen wir lediglich die Tabelle tblBenutzer. Wir erstellen dazu ein Formular, mit dem der Benutzer seinen Benutzernamen sowie das Kennwort eingeben kann und das dann prüft, ob die Daten mit den gespeicherten Daten übereinstimmen. Falls nicht, kann der Benutzer sich bei Bedarf ein neues Kennwort zusenden lassen beziehungsweise dieses ändern. Im zweiten Teil verwenden Sie die Daten der aktuellen Anmeldung dann dazu, um die Berechtigung für diesen Benutzer an einer bestimmten Tabelle zu ermitteln. Dazu definieren wir eine passende VBA-Funktion. Hier kommen dann alle Tabellen der Berechtigungsverwaltung zum Einsatz.

Datenmodell der Berechtigungsverwaltung

Bild 1: Datenmodell der Berechtigungsverwaltung

Anmeldeformular programmieren

Im ersten Teil programmieren wir das Anmeldeformular. Das sollte normalerweise schnell zu erledigen sein, aber in der Tat kann man ein solches Formular beliebig kompliziert gestalten. In unserem Fall wollen wir damit starten, zwei Textfelder zur Eingabe von Benutzername und Kennwort bereitzustellen sowie eine Schaltfläche zum Bestätigen der Eingabe und eine zum Beenden der Anmeldung, die dann auch die Anwendung schließt. Der Entwurf sieht also im ersten Anlauf etwa wie in Bild 2 aus.

Entwurf des Anmeldeformulars

Bild 2: Entwurf des Anmeldeformulars

Das Formular enthält nun neben dem Bezeichnungsfeld mit dem Text Anmeldung die folgenden Steuer-elemente:

  • txtBenutzername: Textfeld zur Eingabe des Benutzernamens
  • txtKennwort: Textfeld zur Eingabe des Kennworts mit einem Eingabeformat zum Maskieren der Eingabe
  • cmdAnmelden: Schaltfläche, die eine Prozedur zum Prüfen der Kombination aus Benutzername und Kennwort aufruft
  • cmdAbbrechen: Schaltfläche, die das Formular und die Anwendung schließt

Für das Textfeld txtKennwort legen wir das Eingabeformat Kennwort fest. Dazu klicken Sie rechts in der Eigenschaft Eingabeformat für dieses Textfeld auf die Schaltfläche mit den drei Punkten (). Es erscheint der Dialog Eingabeformat-Assistent, wo Sie das Eingabeformat Kennwort auswählen (siehe Bild 3).

Einstellen des Eingabeformats

Bild 3: Einstellen des Eingabeformats

Anschließend wird die Eingabe des Textes im Textfeld txtKennwort durch Sternchen maskiert (siehe Bild 4). An dieser Stelle legen wir für die Eigenschaften Datensatzmarkierer, Navigationsschaltflächen, Bildlaufleisten und Trennlinien den Wert Nein und für Automatisch zentrieren den Wert Ja fest, damit die entsprechenden Elemente nicht mehr erscheinen beziehungsweise das Anmeldeformular in der Mitte des Access-Fensters angezeigt wird.

Verbergen der Kennworteingabe

Bild 4: Verbergen der Kennworteingabe

Prüfen von Benutzername und Kennwort

Wenn der Benutzer auf die Schaltfläche cmdAnmelden klickt, soll eine Prozedur prüfen, ob Benutzername und Kennwort zusammengehören. Diese gestalten wir erst einmal so einfach wie möglich. Die Ereignisprozedur soll erst einmal prüfen, ob Benutzername und Kennwort zusammenpassen und in diesem Fall ein Meldungsfenster mit dem Ergebnis anzeigen. Das Gleiche soll geschehen, wenn die Kombination aus Benutzername und Kennwort nicht in der Tabelle tblBenutzer gespeichert ist:

Private Sub cmdAnmelden_Click()
     If AnmeldungPruefen(Me!txtBenutzername, _
             Me!txtKennwort) = True Then
         MsgBox "Anmeldung erfolgreich."
     Else
         MsgBox "Anmeldung nicht erfolgreich."
     End If
End Sub

Die Funktion AnmeldungPruefen finden Sie in Listing 1. Die Funktion berücksichtigt, dass wir die Kennwörter nicht im Klartext im Feld Kennwort der Tabelle tblBenutzer speichern, sondern in verschlüsselter Form. Sie nimmt die zu untersuchende Kombination von Benutzername und Kennwort in Form der beiden Parameter strBenutzername und strKennwort entgegen. Dann erstellt sie eine neue Instanz der Klasse clsCrypt, die unter anderem eine Methode zum Verschlüsseln mit dem SHA1-Algorithmus bereitstellt. Diese Methode verschlüsselt dann das Kennwort aus strKennwort. Das Ergebnis landet in der Variablen strVerschluesselt.

Public Function AnmeldungPruefen(strBenutzername As String, strKennwort As String)
     Dim objCrypt As clsCrypt
     Dim strVerschluesselt As String
     Set objCrypt = New clsCrypt
     strVerschluesselt = objCrypt.GetSHA1(strKennwort)
     If Not IsNull(DLookup("BenutzerID", "tblBenutzer", "Benutzername = ''" & strBenutzername & "'' AND Kennwort = ''" _
             & strVerschluesselt & "''")) Then
         AnmeldungPruefen = True
     End If
End Function

Listing 1: Funktion zum Prüfen einer Anmeldung

Damit können wir dann über den Aufruf einer DLookup-Funktion prüfen, ob die Kombination aus Benutzername und SHA1-verschlüsseltem Kennwort in der Tabelle tblBenutzer vorkommt. Ist dies der Fall, liefert die Funktion AnmeldungPruefen den Wert True zurück, anderenfalls den Wert False.

Nach der Anmeldung

Was soll nach der Anmeldung geschehen Als Erstes sollte der Anmeldedialog geschlossen werden. Dann speichern wir den Benutzernamen des angemeldeten Benutzers in irgendeiner Form. Aber welche ist die geeignete Form – eine öffentliche Variable Nein, denn wir wollen später im Beitrag Zugriffsrechte mit Datenmakros (www.access-im-unternehmen.de/1193) auch auf diese Information zugreifen.

Das ist dort am einfachsten möglich über eine in der TempVars-Auflistung gespeicherte Variable.

Also ersetzen wir die MsgBox-Anweisung in der Prozedur cmdAnmelden_Click durch die folgenden beiden Zeilen:

If AnmeldungPruefen(Me!txtBenutzername, Me!txtKennwort) = True Then
     TempVars.Add "Benutzername", Me!txtBenutzername.Value
     DoCmd.Close acForm, Me.Name
Else

Danach können wir wie folgt auf den Wert der temporären Variablen zugreifen:

Debug.Print TempVars!Benutzername
Peter Gross

Wenn die Anmeldung fehlschlägt, soll die temporäre Variable übrigens wieder geleert werden:

TempVars.Remove "Benutzername"

Bei nicht erfolgreicher Anmeldung

Wenn der Benutzer nicht die richtigen Daten eingibt, erscheint aktuell jeweils die Meldung mit dem Text Anmeldung nicht erfolgreich. Hier könnten wir nun beispielsweise prüfen, ob ein Benutzer mehrfach versucht, sich mit dem gleichen Benutzernamen anzumelden und dabei immer wieder das falsche Kennwort eingibt.

Ist das der Fall, könnte man verschiedene Aktionen durchführen – beispielsweise die Zeit zwischen den möglichen Anmeldeversuchen schrittweise vergrößern, um zu verhindern, dass jemand automatisiert versucht, das Kennwort für den Benutzernamen zu ermitteln.

Hier wird es schon interessant, denn diese Informationen müssen wir ebenfalls speichern, um beim nächsten Anmeldeversuch wieder darauf zugreifen zu können. Zunächst legen wir fest, wieviel Zeit zwischen zwei Anmeldeversuchen verstreichen soll.

Wir beginnen ganz entspannt und legen fest, dass zwischen den ersten und dem zweiten Versuch eine Sekunde verstreichen soll. Das merkt der Benutzer gar nicht, da die Eingabe des Kennworts ja mindestens eine Sekunde dauern sollte.

Von nun an verdoppeln wir die Zeit mit jedem Versuch. Nach dem zweiten Versuch muss er also zwei Sekunden warten, nach dem dritten Versuch vier Sekunden und so weiter. So wächst die Wartezeit zwischen zwei Anmeldeversuchen schnell an.

Welche Informationen müssen wir dazu speichern Wir benötigen den Benutzernamen, denn die Anmeldungen sollen nur für Versuche mit dem gleichen Benutzernamen gezählt werden. Dann benötigen wir die Anzahl der Versuche seit der letzten erfolgreichen Anmeldung und den Zeitpunkt des letzten erfolglosen Versuchs.

Diese Informationen können wir am besten direkt in der Benutzertabelle speichern, da diese ja ohnehin bereits für jeden Benutzer einen Datensatz enthält. Also fügen wir die folgenden Felder wie in Bild 5 hinzu:

Neue Felder in der Tabelle tblBenutzer

Bild 5: Neue Felder in der Tabelle tblBenutzer

  • LetzteErfolgreicheAnmeldung: Datum und Uhrzeit des letzten erfolgreichen Anmeldeversuchs
  • LetzteFehlgeschlageneAnmeldung: Datum und Uhrzeit des letzten fehlgeschlagenen Anmeldeversuchs
  • AnzahlFehlgeschlageneAnmeldungen: Anzahl der fehlgeschlagenen Anmeldungen seit der letzten erfolgreichen Anmeldung

Integration der Wartezeit in den Anmeldedialog

Die Daten dieser drei Felder ändern wir bei jedem fehlgeschlagenen und auch bei jedem erfolgreichen Anmeldeversuch. Bei einem erfolgreichen Anmeldeversuch tragen wir Datum und Zeit dieses Versuchs in das Feld LetzteErfolgreicheAnmeldung ein und stellen den Wert des Feldes AnzahlFehlgeschlageneAnmeldungen auf 0 ein.

Bei einem gescheiterten Anmeldeversuch stellen wir das Feld LetzteFehlgeschlageneAnmeldung auf das aktuelle Datum plus Uhrzeit ein und erhöhen den Wert des Feldes AnzahlFehlgeschlageneAnmeldungen um 1.

Auf diese Weise können wir allerdings nur Anmeldeversuche behandeln, für die ein gültiger Benutzername angegeben wurde. Wenn kein Benutzername angegeben wurde, können wir auch keine Informationen über die letzte Anmeldung des Benutzers in der Tabelle tblBenutzer speichern. Wie gehen wir dann vor Ignorieren wir Anmeldeversuche ohne gültigen Benutzernamen, weil der Benutzer – auch wenn er böse Absichten hat – ohne Kenntnis eines gültigen Benutzernamens noch weiter von einer erfolgreichen Anmeldung entfernt ist als mit Benutzername Oder sollten wir auch hier eine zeitliche Barriere einführen Wir wollen es einfach halten und ignorieren Anmeldungen ohne gültigen Benutzernamen einfach.

Die Funktion AnmeldungPruefen ändern wir wie in Listing 2. Wir haben statt der DLookup-Funktion direkt den Zugriff auf den Datensatz der Tabelle tblBenutzer mit dem passenden Benutzernamen als Recordset implementiert. Das heißt, dass wir nach dem Ermitteln des verschlüsselten Kennworts ein Recordset öffnen, das den Datensatz der Tabelle tblBenutzer mit dem Benutzernamen aus dem Parameter strBenutzername enthält. Ist dieses Recordset leer, hat der Benutzer einen ungültigen Benutzernamen eingegeben und die Funktion soll den Wert False zurückliefern. Ist das Recordset nicht leer, hat der Benutzer zumindest einen gültigen Benutzernamen angegeben.

Public Function AnmeldungPruefen(strBenutzername As String, strKennwort As String)
     Dim objCrypt As clsCrypt
     Dim strVerschluesselt As String
     Dim db As DAO.Database
     Dim rst As DAO.Recordset
     Set db = CurrentDb
     Set objCrypt = New clsCrypt
     strVerschluesselt = objCrypt.GetSHA1(strKennwort)
     Set rst = db.OpenRecordset("SELECT * FROM tblBenutzer WHERE Benutzername = ''" & strBenutzername & "''", dbOpenDynaset)
     If Not rst.EOF Then
         If strVerschluesselt = rst!Kennwort Then
             rst.Edit
             rst!LetzteErfolgreicheAnmeldung = Now
             rst!AnzahlFehlgeschlageneAnmeldungen = 0
             rst.Update
             AnmeldungPruefen = True
         Else
             rst.Edit
             rst!LetzteFehlgeschlageneAnmeldung = Now
             rst!AnzahlFehlgeschlageneAnmeldungen = Nz(rst!AnzahlFehlgeschlageneAnmeldungen, 0) + 1
             rst.Update
             AnmeldungPruefen = False
         End If
     Else
         AnmeldungPruefen = False
     End If
End Function

Listing 2: Funktion zum Prüfen einer Anmeldung, erweiterte Fassung

Dann prüfen wir in einer If…Then-Bedingung, ob das verschlüsselte Kennwort aus strVerschluesselt mit der im Feld Kennwort gespeicherten, verschlüsselten Version des Kennworts für diesen Benutzer übereinstimmt. In diesem Fall versetzen wir das Recordset mit der Edit-Methode in den Verarbeitungsmodus und stellen zwei Felder auf neue Werte ein. Das Feld LetzteErfolgreicheAnmeldung erhält mit der Funktion Now das aktuelle Datum plus Uhrzeit, das Feld AnzahlFehlgeschlageneAnmeldungen stellen wir auf den Wert 0 ein. Danach speichern wir den aktualisierten Datensatz mit der Update-Methode und geben den Wert True als Funktionswert zurück.

Stimmt das verschlüsselte Kennwort nicht mit dem Wert aus dem Feld Kennwort überein, bearbeiten wir den aktuellen Datensatz ebenfalls. Hier legen wir den Wert des Feldes LetzteFehlgeschlageneAnmeldung auf das Ergebnis der Funktion Now fest und erhöhen den Wert des Feldes AnzahlFehlgeschlageneAnmeldungen auf den vorherigen Wert plus 1. Falls das Feld vorher noch leer war, erhält das Feld den Wert 1. In diesem Fall geben wir den Wert False als Funktionsergebnis zurück.

Der entsprechende Datensatz sieht nach drei fehlgeschlagenen Anmeldungen und ohne erfolgreiche Anmeldung beispielsweise wie in Bild 6 aus.

Speichern fehlgeschlagener Anmeldungen

Bild 6: Speichern fehlgeschlagener Anmeldungen

Zeitverzögerung beim Anmelden

Nun müssen wir noch dafür sorgen, dass das Formular frmAnmeldung beim Versuch, sich unter einem Benutzernamen anzumelden, für den es seit der letzten erfolgreichen Anmeldung einen oder mehrere fehlgeschlagene Anmeldungen gab, eine zeitliche Sperre einrichtet und den Benutzer auch darüber informiert.

Was wir dafür zweifelsohne benötigen, ist die Ereignisprozedur Bei Zeitgeber sowie ein entsprechendes Intervall für die Eigenschaft Zeitgeberintervall, das angibt, nach welchem Zeitraum das Ereignis Bei Zeitgeber das nächste Mal ausgelöst werden soll. Die Eigenschaft Zeitgeberintervall statten wir mit dem Zeitraum über eine Sekunde aus, was dem Wert 1.000 (in Millisekunden) entspricht.

Ende des frei verfügbaren Teil. Wenn Du mehr lesen möchtest, hole Dir ...

Testzugang

eine Woche kostenlosen Zugriff auf diesen und mehr als 1.000 weitere Artikel

diesen und alle anderen Artikel mit dem Jahresabo

Schreibe einen Kommentar