{"id":55000688,"date":"2009-10-01T00:00:00","date_gmt":"2020-05-22T22:18:09","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=688"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Benutzerverwaltung","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/","title":{"rendered":"Benutzerverwaltung"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>Bis Access 2003 unterst&uuml;tzte Access den Entwickler durch eine Benutzerverwaltung inklusive Sicherheitssystem. Neuere Access-Versionen bieten dies nicht mehr. Kein gro&szlig;es Problem: Das Sicherheitssystem war ohnehin nicht besonders effektiv, und die Benutzerverwaltung m&ouml;chten Sie vielleicht ohnehin selbst gestalten. In diesem Beitrag zeigen wir, wie Sie eine solche Benutzerverwaltung selbst erstellen und einsetzen.<\/b><\/p>\n<p>Unsere Benutzerverwaltung dient nicht als Ersatz f&uuml;r die bis Access 2003 verf&uuml;gbare, eingebaute Benutzerverwaltung. Das darin enthaltene Sicherheitssystem werden wir nicht &uuml;bernehmen. Der Grund ist einfach: Es ist schwierig, ein Sicherheitssystem zu implementieren, wenn die Datenbank-Engine keine M&ouml;glichkeiten f&uuml;r die Durchsetzung der dort festgelegten Regeln bietet. Dies ist zwar im SQL Server m&ouml;glich und auch unter MySQL und anderen Systemen, aber die Jet Engine von Access bietet dies nicht &#8211; zumindest nicht offiziell. Intern ist ein Teil des Sicherheitssystems zwar noch vorhanden (das merken Sie, wenn Sie versuchen, Systemtabellen von Access zu ver&auml;ndern), aber es wird von Microsoft offiziell nicht mehr unterst&uuml;tzt. Das Unternehmen verfolgt damit wohl zwei Ziele: erstens die Abkehr vom unzuverl&auml;ssigen Sicherheitssystem und zweitens die Nutzung von aktiven Datenbankmanagementsystemen mit &Atilde;&#8220;&#8220;echter&Atilde;&#8220;&#8220; Benutzerverwaltung.<\/p>\n<p>In diesem Beitrag lassen wir den Sicherheitsaspekt weitgehend au&szlig;er Acht &#8211; zumindest insofern, dass wir den direkten Zugriff auf Tabellen nicht unterbinden. Stattdessen konzentrieren wir uns darauf, Tabellen bereitzustellen, mit denen Sie Benutzer und Benutzergruppen erfassen k&ouml;nnen. Diese sollen &uuml;ber entsprechende Formulare gef&uuml;llt werden. Zus&auml;tzlich gibt es noch einen Anmeldedialog, &uuml;ber den der Benutzer sich mit Benutzername und gegebenenfalls einem Kennwort anmeldet. Diese Anmeldedaten der aktuellen Sitzung speichern wir an geeigneter Stelle und erstellen Funktionen, die f&uuml;r den angemeldeten Benutzer freigegebene Features ermitteln.<\/p>\n<p><b>Einfache Variante<\/b><\/p>\n<p>Im einfachsten Fall reicht f&uuml;r die Verwaltung von Benutzern eine Benutzertabelle aus. Sie w&uuml;rden darin lediglich Basisinformationen wie den realen Namen des Benutzers sowie seinen Benutzernamen und gegebenenfalls ein Kennwort speichern. <\/p>\n<p>Was k&ouml;nnen Sie mit dieser Variante anfangen Im Prinzip alles, was Sie auch mit einer um Benutzergruppen erweiterten Version erledigen k&ouml;nnen. Allerdings wird es dann kompliziert, wenn Sie viele Benutzer verwalten und f&uuml;r diese etwa festlegen m&ouml;chten, welcher Benutzer welche Men&uuml;befehle ausf&uuml;hren oder Formulare &ouml;ffnen darf: Hier kommt es oft vor, dass mehrere Benutzer die gleichen Berechtigungen erhalten sollen, was bei Verwendung von Benutzergruppen deutlich vereinfacht werden kann.<\/p>\n<p>Wenn Sie die Benutzerverwaltung aber nur f&uuml;r individuelle, benutzerabh&auml;ngige Aufgaben verwenden m&ouml;chten, reicht eine einzige Benutzertabelle ohne Benutzerverwaltung v&ouml;llig aus. Das Paradebeispiel hierf&uuml;r ist das Protokollieren von Zugriffen auf und &auml;nderungen an den Daten einer Datenbank. Dies geschieht immer in Abh&auml;ngigkeit vom einzelnen Benutzer und erfordert somit nicht die Angabe seiner Benutzergruppe. Die hier verwendete Tabelle sieht beispielsweise wie in Bild 1 aus. Beachten Sie, dass jeder Benutzername nur einmal vorkommen soll. Daher stellen Sie den Wert der Eigenschaft <b>Indiziert <\/b>f&uuml;r das Feld <b>Benutzername <\/b>auf den Wert <b>Ja (Ohne Duplikate) <\/b>ein.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic002_opt.jpeg\" alt=\"pic002.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 2: Diese Tabelle speichert unter anderem den angemeldeten Benutzer.<\/span><\/b><\/p>\n<p>Wer Informationen in Abh&auml;ngigkeit vom aktuell angemeldeten Benutzer speichern m&ouml;chte, muss zun&auml;chst an geeigneter Stelle festhalten, welcher Benutzer gerade angemeldet ist. Dazu sind zwei Voraussetzungen notwendig:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Eine Tabelle, welche die ID des aktuellen Benutzers speichert.<\/li>\n<li class=\"aufz-hlung\">Ein Formular, mit dem sich der Benutzer beim Start der Anwendung anmeldet.<\/li>\n<\/ul>\n<p><b>Angemeldeten Benutzer merken<\/b><\/p>\n<p>Die Tabelle zum Speichern des aktuell angemeldeten Benutzers soll eine einfache Optionen-Tabelle sein. Diese hei&szlig;t <b>tblOptionen <\/b>und enth&auml;lt die drei Felder <b>OptionID <\/b>(Autowert), <b>Optionsname <\/b>und <b>Optionswert <\/b>(beides Textfelder) und sieht im Entwurf wie in Bild 2 aus.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic001_opt.jpeg\" alt=\"pic001.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 1: Entwurf der Tabelle zum Speichern von Benutzern<\/span><\/b><\/p>\n<p>Unabh&auml;ngig vom Formular, das die Anmeldung des Benutzers beim Anwendungsstart entgegennimmt, schreiben wir nun eine kleine Funktion, welche den Optionswert zu einem bestimmten Optionsnamen in dieser Tabelle speichert.<\/p>\n<p>Dazu &ouml;ffnen Sie den VBA-Editor (zum Beispiel mit der Tastenkombination <b>Alt + F11<\/b>) und w&auml;hlen dort den Men&uuml;befehl <b>Einf&uuml;gen|Modul <\/b>aus. Im nun erscheinenden Codefenster f&uuml;gen Sie die Prozedur aus Listing 1 ein. Die Funktion rufen Sie wie folgt auf:<\/p>\n<p class=\"kastentabelleheader\">Listing 1: Mit dieser Funktion speichern Sie Optionen in der Tabelle tblOptionen.<\/p>\n<pre>Public Function OptionEinstellen(strOptionsname As String, strOptionswert As String) As Boolean\r\n    Dim db As DAO.Database\r\n    Set db = CurrentDb\r\n    db.Execute &quot;UPDATE tblOptionen SET Optionswert = ''''&quot; &amp; strOptionswert _\r\n    &amp; &quot;'''' WHERE Optionsname = ''''&quot; &amp; strOptionsname &amp; &quot;''''&quot;, dbFailOnError\r\n    If db.RecordsAffected = 1 Then\r\n        OptionEinstellen = True\r\n        Exit Function\r\n    Else\r\n        If db.RecordsAffected &gt; 1 Then\r\n            db.Execute &quot;DELETE FROM tblOptionen WHERE Optionsname = ''''&quot; _\r\n            &amp; strOptionsname &amp; &quot;''''&quot;, dbFailOnError\r\n        End If\r\n        db.Execute &quot;INSERT INTO tblOptionen(Optionsname, Optionswert) VALUES(''''&quot; &amp; strOptionsname _\r\n        &amp; &quot;'''', ''''&quot; &amp; strOptionswert &amp; &quot;'''')&quot;, dbFailOnError\r\n        If db.RecordsAffected = 1 Then\r\n            OptionEinstellen = True\r\n            Exit Function\r\n        End If\r\n    End If\r\nEnd Function\r\nOptionEinstellen &quot;CurrentUserID&quot;, 1<\/pre>\n<p>Die Funktion <b>OptionEinstellen <\/b>deklariert und instanziert ein Objekt des Typs <b>Database <\/b>mit einem Verweis auf die aktuelle Datenbank und verwendet dessen <b>Execute<\/b>-Methode, um SQL-Aktualisierungsabfragen aufzurufen. Davon gibt es zwei, von denen eine auf jeden Fall, eine weitere nach Bedarf aufgerufen wird. Die erste aktualisiert alle Datens&auml;tze der Tabelle <b>tblOptionen<\/b>, bei denen das Feld <b>Optionsname <\/b>den mit dem Parameter <b>strOptionsname <\/b>&uuml;bergebenen Wert enth&auml;lt und stellt f&uuml;r diese Datens&auml;tze den Inhalt von <b>Optionswert <\/b>auf den mit <b>strOptionswert <\/b>&uuml;bergebenen Wert ein.<\/p>\n<p>Die nachfolgende <b>RecordAffected<\/b>-Methode pr&uuml;ft, ob die Anzahl der durch diese Aktionsabfrage betroffenen Datens&auml;tze gleich eins ist &#8211; dies bedeutet, dass bereits ein Datensatz f&uuml;r die angegebene Option vorhanden war und dieser nun neu eingestellt wurde.<\/p>\n<p>Liefert <b>RecordsAffected<\/b> einen anderen Wert als eins zur&uuml;ck, k&ouml;nnen zwei Probleme aufgetreten sein:<\/p>\n<ul>\n<li class=\"aufz-hlung\"><b>RecordsAffected <\/b>hat einen Wert gr&ouml;&szlig;er eins, was bedeutet, dass die Option bereits mehrfach angelegt wurde. Kein Problem: Die innerhalb der <b>If&#8230;Then<\/b>-Bedingung angegebene Aktionsabfrage l&ouml;scht einfach alle Datens&auml;tze der Tabelle <b>tblOptionen <\/b>mit dem angegebenen Wert im Feld <b>Optionsname<\/b> &#8211; es soll nur einen Datensatz je Option geben, und der wird gleich neu angelegt.<\/li>\n<li class=\"aufz-hlung\">Anderenfalls liefert <b>RecordsAffected <\/b>den Wert <b>0 <\/b>zur&uuml;ck.<\/li>\n<\/ul>\n<p>Erreicht die Prozedur die Zeile hinter der Zeile <b>If db.RecordsAffected &gt; 1 Then<\/b>, ist auf keinen Fall mehr ein Optionsdatensatz mit dem angegebenen Optionsnamen mehr vorhanden, wodurch dieser gleich neu angelegt werden kann &#8211; und das erledigt die folgende <b>INSERT INTO<\/b>-Aktionsabfrage.<\/p>\n<p><b>Formular zur Abfrage des Benutzers<\/b><\/p>\n<p>F&uuml;r den Moment gehen wir davon aus, das ein Formular zur Verwaltung von Benutzern vorhanden ist und dass bereits einige Benutzerdatens&auml;tze in der Tabelle <b>tblBenutzer <\/b>vorliegen (siehe Bild 3).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic003_opt.jpeg\" alt=\"pic003.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 3: Die Tabelle tblBenutzer mit einigen Beispieldaten<\/span><\/b><\/p>\n<p>Darauf bauen wir nun ein Formular auf, dass als Anmeldeformular der Anwendung dienen soll. Das Formular soll im Wesentlichen zwei Textfelder zur Eingabe von Benutzername und Kennwort sowie eine Schaltfl&auml;che zum Abschlie&szlig;en der Eingabe enthalten. Das erste Textfeld hei&szlig;t <b>txtBenutzername<\/b>, das zweite <b>txtKennwort<\/b>. Die Schaltfl&auml;che zum Abschlie&szlig;en der Eingabe hei&szlig;t <b>cmdLogin<\/b>, und au&szlig;erdem ben&ouml;tigen wir noch eine Schaltfl&auml;che zum Abbrechen des Logins namens <b>cmdAbbrechen<\/b>. Der Grobentwurf sieht erstmal so wie in Bild 4 aus.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic004_opt.jpeg\" alt=\"pic004.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 4: Entwurf des Login-Formulars<\/span><\/b><\/p>\n<p>Das normale Einloggen verl&auml;uft wie folgt: Der Benutzer gibt einen Benutzernamen und sein Kennwort ein und klickt auf die <b>Login<\/b>-Schaltfl&auml;che. Die dahinter verborgene Ereignisprozedur pr&uuml;ft, ob das Kennwort zum Benutzernamen stimmt, und tr&auml;gt den neuen aktuellen Benutzer gegebenenfalls in die Optionen-Tabelle ein. Neben dieser Kombination aus g&uuml;ltigem Benutzernamen und passendem Kennwort gibt es jedoch noch weitere Varianten, die das <b>Login<\/b>-Formular ber&uuml;cksichtigen muss:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Der Benutzername ist vorhanden, aber das Kennwort ist falsch.<\/li>\n<li class=\"aufz-hlung\">Der Benutzername ist nicht vorhanden.<\/li>\n<\/ul>\n<p>In beiden F&auml;llen soll der Benutzer eine Nachricht erhalten und erneut mit dem Login-Formular konfrontiert werden. Auch hier gibt es mehrere M&ouml;glichkeiten: Beide Textfelder behalten ihren Wert, beide Textfelder werden gel&ouml;scht oder der Benutzername wird beibehalten und nur das Kennwortfeld wird gel&ouml;scht &#8211; das ist der Fall, wenn der Benutzername richtig und das Kennwort falsch ist.<\/p>\n<p>All dies wird zur blassen Theorie, denn wir arbeiten ja mit Access und wollen seine Mittel aussch&ouml;pfen. Die Benutzernamen der f&uuml;r die Anwendung registrierten Benutzer sind in der Tabelle <b>tblBenutzer <\/b>gespeichert. Warum sollte man den Benutzer also auf umst&auml;ndliche Weise seinen Benutzernamen eingeben lassen Je nach der Konvention, die f&uuml;r die Zusammenstellung des Benutzernamens gew&auml;hlt wurde (falls es denn eine gibt), kann es durchaus vorkommen, dass man seinen Benutzernamen einmal vergisst. Also werfen wir das Textfeld <b>txtBenutzername <\/b>raus, bevor wir richtig loslegen, und ersetzen es durch ein Kombinationsfeld namens <b>cboBenutzername<\/b>. Dieses passen wir durch Einstellen der folgenden Eigenschaften an:<\/p>\n<ul>\n<li class=\"aufz-hlung\"><b>Datensatzherkunft<\/b>: <b>SELECT Benutzername FROM tblBenutzer ORDER BY Benutzername<\/b><\/li>\n<li class=\"aufz-hlung\"><b>Spaltenanzahl<\/b>: <b>1<\/b><\/li>\n<li class=\"aufz-hlung\"><b>Spaltenbreiten<\/b>: <b>leer<\/b><\/li>\n<\/ul>\n<p>Auch das Textfeld <b>txtKennwort <\/b>zur Eingabe des Kennworts passen wir noch so an, dass die Kennworteingabe wie in einer professionellen Anwendung aussieht. Dort erscheinen statt des Kennworts im Klartext bei der Eingabe Platzhalter wie etwa das Sternchen (*). Diese Einstellung nehmen Sie vor, indem Sie die Eigenschaft <b>Eingabeformat <\/b>des Textfelds anklicken, die daraufhin erscheinende Schaltfl&auml;che mit den drei Punkten (&#8230;) bet&auml;tigen und im Dialog aus Bild 5 den Eintrag <b>Kennwort <\/b>ausw&auml;hlen.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic005_opt.jpeg\" alt=\"pic005.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 5: So sorgen Sie daf&uuml;r, dass Dritte Kennw&ouml;rter bei der Eingabe nicht mitlesen k&ouml;nnen.<\/span><\/b><\/p>\n<p class=\"zwischen-berschrift-oberer-spaltenrand\">Login bei Eingabetaste<\/p>\n<p>Wenn der Benutzer auf einem Webformular die Eingabetaste dr&uuml;ckt, bewirkt dies &uuml;blicherweise das Absenden der im Formular eingetragenen Daten. Dieses im Internet g&auml;ngige Verhalten kann man auch beim Benutzer einer Datenbankanwendung als bekannt voraussetzen: Wenn dieser schon nicht mit der Maus von Eingabefeld zu Eingabefeld navigiert und die Eingabe mit einem Klick auf die entsprechende Schaltfl&auml;che abschlie&szlig;t, erledigt er dies in der Regel mit der Tabulator-Taste und schlie&szlig;t die Eingabe mit der Eingabetaste ab.<\/p>\n<p>Dies soll auch hier der Fall sein. Ungeachtet der beim Abschlie&szlig;en der Anmeldung ausgef&uuml;hrten Codezeilen schauen wir uns erst einmal an, wie wir Access dazu bewegen, beim Klick auf die Eingabetaste das Gleiche zu tun wie beim Bet&auml;tigen der <b>Login<\/b>-Schaltfl&auml;che. Dies verlangt nach Weniger, als Sie wahrscheinlich vermuten: Sie m&uuml;ssen lediglich die Eigenschaft <b>Standard <\/b>der Schaltfl&auml;che <b>cmdLogin <\/b>auf den Wert <b>Ja <\/b>einstellen.<\/p>\n<p>Damit definieren Sie diese Schaltfl&auml;che als Standardschaltfl&auml;che des Formulars, die beim Klick auf die Eingabetaste automatisch ausgel&ouml;st wird. Das Gleiche ist &uuml;brigens auch f&uuml;r die <b>Abbrechen<\/b>-Schaltfl&auml;che m&ouml;glich: Hier verwenden Sie allerdings die Eigenschaft <b>Abbrechen <\/b>der entsprechenden Schaltfl&auml;che, die Sie ebenfalls auf den Wert <b>Ja <\/b>einstellen. In diesem Fall f&uuml;hrt das Bet&auml;tigen der <b>Escape<\/b>-Taste zum Ausf&uuml;hren der f&uuml;r die <b>Abbrechen<\/b>-Schaltfl&auml;che hinterlegten Ereignisprozedur.<\/p>\n<p>Beachten Sie aber, dass dies nicht funktioniert, wenn eine andere Schaltfl&auml;che bereits den Fokus besitzt, weil der Benutzer diese beispielsweise durch mehrfaches Bet&auml;tigen der Tabulatortaste aktiviert hat.<\/p>\n<p><b>Benutzername und Kennwort pr&uuml;fen<\/b><\/p>\n<p>Damit Sie das Verhalten der Schaltfl&auml;chen und der damit verbundenen Tasten <b>Enter <\/b>und <b>Escape <\/b>pr&uuml;fen k&ouml;nnen, legen Sie nun entsprechende Ereignisprozeduren f&uuml;r die <b>Beim Klicken<\/b>-Ereigniseigenschaften dieser Steuerelemente an.<\/p>\n<p>Am einfachsten gelingt dies mit der Schaltfl&auml;che <b>cmdAbbrechen<\/b>: Diese soll bei Bet&auml;tigung einfach die aktuelle Anwendung beenden, wenn der Benutzer sich nicht einloggen will oder kann. Sicherheitshalber soll die Anwendung den Benutzer noch fragen, ob dieser sicher ist, dass er die Anwendung beenden m&ouml;chte. Dies sieht wie folgt aus:<\/p>\n<pre>Private Sub cmdAbbrechen_Click()\r\n    If MsgBox(&quot;Dies beendet die Anwendung.\r\n    Fortsetzen&quot;, vbYesNo + vbExclamation,\r\n    &quot;Anwendung beenden&quot;) = vbYes Then\r\n    DoCmd.Quit\r\nEnd If\r\nEnd Sub<\/pre>\n<p>Die Prozedur, welche die Benutzereingaben pr&uuml;fen soll, f&auml;llt etwas l&auml;nger, aber nicht komplizierter aus:<\/p>\n<pre>Private Sub cmdLogin_Click()\r\nDim lngBenutzerID As Long\r\nlngBenutzerID = Nz(DLookup(&quot;BenutzerID&quot;, _\r\n&quot;tblBenutzer&quot;, &quot;Benutzername = ''''&quot; _\r\n&amp; Me!cboBenutzername _\r\n&amp; &quot;'''' AND Kennwort = ''''&quot; _\r\n&amp; Me!txtKennwort &amp; &quot;''''&quot;), 0)\r\nIf lngBenutzerID = 0 Then\r\n MsgBox &quot;Benutzername und\/oder &quot; _\r\n    &amp; &quot;Kennwort sind falsch.&quot;\r\nElse\r\n MsgBox &quot;Anmeldung erfolgreich!&quot;\r\n    OptionEinstellen &quot;CurrentUserID&quot;, _\r\n    CStr(lngBenutzerID)\r\n    DoCmd.Close acForm, Me.Name\r\nEnd If\r\nEnd Sub<\/pre>\n<p>Die Routine verwendet die <b>DLookup<\/b>-Anweisung, um den Wert des Feldes <b>BenutzerID <\/b>f&uuml;r einen Datensatz der Tabelle <b>tblBenutzer <\/b>zu ermitteln, bei dem die Inhalte der Felder <b>Benutzername <\/b>und <b>Kennwort <\/b>mit den Inhalten der Textfelder <b>txtBenutzername <\/b>und <b>txtKennwort <\/b>&uuml;bereinstimmen.<\/p>\n<p>Wenn <b>DLookup <\/b>keinen passenden Datensatz findet, liefert es den Wert <b>Null <\/b>zur&uuml;ck &#8211; und dann tritt die <b>Nz<\/b>-Funktion auf den Plan, die den Wert <b>Null <\/b>durch den im zweiten Parameter angegebenen Wert ersetzt, in diesem Fall die Zahl <b>0<\/b>. Diese wird schlie&szlig;lich in der Variablen <b>lngCurrentUserID <\/b>gespeichert.<\/p>\n<p>Die nachfolgende <b>If&#8230;Then<\/b>-Bedingung pr&uuml;ft genau auf diesen Wert und verzweigt zu einer von zwei M&ouml;glichkeiten:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Ist der Wert von <b>lngCurrentUserID 0<\/b>, dann hat der Benutzer nicht die richtigen Daten eingegeben &#8211; es erscheint eine entsprechende Meldung und das Anmeldeformular bleibt sichtbar.<\/li>\n<li class=\"aufz-hlung\">Ist der Wert ungleich <b>0<\/b>, existiert der angegebene Benutzername samt Kennwort. Der Anmeldedialog wird geschlossen und die <b>BenutzerID <\/b>des aktuellen Benutzers im entsprechenden Datensatz der Tabelle <b>tblBenutzer <\/b>gespeichert.<\/li>\n<\/ul>\n<p><b>Anzeigen des Loginformulars beim Start<\/b><\/p>\n<p>Der Benutzer soll nach dem Start der Anwendung als Erstes das Loginformular sehen, damit er sich anmelden kann. Au&szlig;erdem soll er nicht auf irgendein Element der Anwendung zugreifen k&ouml;nnen, bevor er sich nicht eingeloggt hat und das Loginformular geschlossen ist.<\/p>\n<p>Das gelingt auf zwei Arten:<\/p>\n<ul>\n<li class=\"aufz-hlung\">durch Einstellen bestimmter Eigenschaften des Formulars und Festlegen von <b>frmLogin<\/b> als Startformular der Anwendung in den Eigenschaften der aktuellen Datenbank.<\/li>\n<li class=\"aufz-hlung\">durch Anlegen eines <b>AutoExec<\/b>-Makros mit einem Befehl zum &Ouml;ffnen des Formulars als modalen Dialog.<\/li>\n<\/ul>\n<p>F&uuml;r die erste Variante zeigen Sie zun&auml;chst die Eigenschaften der aktuellen Datenbank an (unter Access 2003 mit dem Men&uuml;befehl <b>Extras|Start<\/b>, unter Access 2007 &uuml;ber die Schaltfl&auml;che <b>Access-Optionen <\/b>des Office-Men&uuml;s und anschlie&szlig;endes Wechseln in den Bereich <b>Aktuelle Datenbank<\/b>, s. Abb. 6). Dort w&auml;hlen Sie f&uuml;r die Eigenschaft <b>Formular anzeigen <\/b>das Formular <b>frmLogin <\/b>aus.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic006_opt.jpeg\" alt=\"pic006.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 6: Einstellen eines Formulars als Startformular<\/span><\/b><\/p>\n<p>Wenn Sie die Anwendung nun neu starten, erscheint das gew&uuml;nschte Formular &#8211; aber der Benutzer kann ohne Eingabe der Logindaten auf die &uuml;brigen Elemente der Anwendung zugreifen und beispielsweise Tabellen &ouml;ffnen.<\/p>\n<p>Sie m&uuml;ssen das Formular noch als modalen Dialog auslegen und dies geschieht durch die folgenden beiden Schritte:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Einstellen der Eigenschaft <b>Popup <\/b>im Eigenschaftsfenster des Formulars auf <b>Ja<\/b>.<\/li>\n<li class=\"aufz-hlung\">Einstellen der Eigenschaft <b>Gebunden <\/b>auf den Wert <b>Ja<\/b>.<\/li>\n<\/ul>\n<p>Bei der zweiten Variante legen Sie zun&auml;chst ein neues Makro an und speichern es unter dem Namen <b>AutoExec<\/b>. Durch Verwendung dieses speziellen Namens wird es gleich beim Start der Anwendung ausgel&ouml;st &#8211; es sei denn, der Benutzer bet&auml;tigt beim Starten die Umschalttaste. Legen Sie dann wie in Bild 7 eine Aktion namens <b>&Ouml;ffnenFormular <\/b>an und legen Sie als Parameter den Formularnamen sowie als <b>Fenstermodus <\/b>den Wert <b>Dialog <\/b>fest. Dies erf&uuml;llt die gleiche Funktion wie das Einstellen der beiden Eigenschaften aus der vorherigen Variante.<\/p>\n<p><b>Feinheiten<\/b><\/p>\n<p>Sie m&uuml;ssen noch einige kleinere Anpassungen vornehmen:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Stellen Sie die Eigenschaften <b>Mit Systemmen&uuml;feld<\/b>, <b>Schlie&szlig;en-Schaltfl&auml;che <\/b>und <b>MinMax-Schaltfl&auml;che <\/b>jeweils auf den Wert <b>Nein <\/b>ein, damit der Benutzer den Dialog nur &uuml;ber die beiden daf&uuml;r vorgesehenen Schaltfl&auml;chen verlassen kann.<\/li>\n<li class=\"aufz-hlung\">Stellen Sie die Eigenschaften <b>Datensatzmarkierer<\/b>, <b>Navigationsschaltfl&auml;chen<\/b>, <b>Bildlaufleisten <\/b>und <b>Trennlinien <\/b>auf den Wert <b>Nein <\/b>ein, damit st&ouml;rende Elemente ausgeblendet werden.<\/li>\n<li class=\"aufz-hlung\">Stellen Sie den Text der Titelleiste des Formulars mit der Eigenschaft <b>Beschriftung <\/b>auf einen Wert wie <b>Login <\/b>oder <b>Anmeldung <\/b>ein.<\/li>\n<\/ul>\n<p>Auch das Verhalten nach Eingabe falscher Benutzerdaten &auml;ndern wir noch: Da wir die Benutzernamen per Kombinationsfeld zur Auswahl bereitstellen, ist die Chance, dass der Benutzer einen falschen Namen ausw&auml;hlt, gering. Die Anmeldung wird also &uuml;blicherweise an der Eingabe des Kennwort scheitern. Damit der Benutzer nach einer Fehleingabe keine unn&ouml;tigen Mimiken ausf&uuml;hren muss, legen wie den Fokus direkt auf das Textfeld <b>txtKennwort<\/b>, und zwar mit einer zus&auml;tzlichen Zeile in der Ereignisprozedur <b>cmdLogin_Click<\/b>:<\/p>\n<pre>[...]\r\nIf lngBenutzerID = 0 Then\r\nMsgBox &quot;Benutzername und\/oder Kennwort sind falsch.&quot;\r\nMe!txtKennwort.SetFocus\r\nElse\r\n[...]<\/pre>\n<p>Das Formular sieht in der Formularansicht nun wie in Bild 8 aus.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic007_opt.jpeg\" alt=\"pic007.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 9: Entwurf der Tabelle tblBenutzergruppen<\/span><\/b><\/p>\n<p><b>Benutzerverwaltung mit Benutzergruppen<\/b><\/p>\n<p>Bevor wir uns ansehen, was wir mit dem angemeldeten Benutzer anstellen k&ouml;nnen, werfen wir noch einen Blick auf die Benutzergruppen. Deren Einrichtung &auml;ndert nichts am Login-Prozedere, aber wir brauchen diese sp&auml;ter, um die Berechtigungen der Benutzer etwa f&uuml;r den Zugriff auf einzelne Elemente von Formularen auch auf Gruppenebene festlegen zu k&ouml;nnen.<\/p>\n<p>Die Tabelle zum Speichern der Benutzergruppen hei&szlig;t <b>tblBenutzergruppen <\/b>und enth&auml;lt nur zwei Felder &#8211; <b>BenutzergruppeID <\/b>und <b>Benutzergruppe<\/b>. Letzteres versehen Sie mit einem eindeutigen Index, damit jede Benutzergruppe einen eindeutigen Namen besitzt (siehe Bild 9). Wie stellen wir aber nun die Beziehung zwischen den in der Tabelle <b>tblBenutzer <\/b>gespeicherten Benutzern und der Benutzergruppe aus <b>tblBenutzergruppen <\/b>her Hier gibt es zwei M&ouml;glichkeiten, die davon abh&auml;ngen, ob ein Benutzer nur einer oder mehreren Gruppen angeh&ouml;ren darf. Wir w&auml;hlen gleich die umfassendere Variante, indem wir &uuml;ber eine Verkn&uuml;pfungstabelle namens <b>tblBenutzerBenutzergruppen <\/b>eine m:n-Beziehung zwischen den beiden Tabellen <b>tblBenutzer <\/b>und <b>tblBenutzergruppen <\/b>herstellen. Den Namen dieser Verkn&uuml;pfungstabelle k&ouml;nnen Sie nach eigenem Gusto anpassen &#8211; sinnvoll w&auml;re ebenso <b>tblBenutzergruppenzuordnung<\/b>. Nach einer in den meisten L&ouml;sungen von Access im Unternehmen verwendeten Konvention w&auml;re die konsequente aber die erstgenannte, bei der dem Pr&auml;fix <b>tbl <\/b>die beiden Objektarten der zu verkn&uuml;pfenden Tabellen im Plural aufgef&uuml;hrt werden.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic009_opt.jpeg\" alt=\"pic009.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 7: Das AutoExec-Makro &ouml;ffnet das Formular frmLogin als modalen Dialog.<\/span><\/b><\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic008_opt.jpeg\" alt=\"pic008.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 8: Das fertige Loginformular<\/span><\/b><\/p>\n<p>Die Verkn&uuml;pfungstabelle besteht aus drei Feldern: einem Prim&auml;rschl&uuml;sselfeld namens <b>ID <\/b>als eindeutigem Index und den beiden Fremdschl&uuml;sselfeldern <b>BenutzerID <\/b>und <b>BenutzergruppeID<\/b>. F&uuml;r diese beiden Felder legen Sie einen zusammengesetzten, eindeutigen Index fest (siehe Bild 10).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic010_opt.jpeg\" alt=\"pic010.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 10: Die Verkn&uuml;pfungstabelle zur Herstellung der m:n-Beziehung zwischen Benutzern und Benutzergruppen<\/span><\/b><\/p>\n<p>Damit f&uuml;r die beiden Felder <b>BenutzerID<\/b> und <b>BenutzergruppeID <\/b>nur solche Werte eingetragen werden k&ouml;nnen, die den Prim&auml;rschl&uuml;sselfeldern der beiden Tabellen <b>tblBenutzer <\/b>und <b>tblBenutzergruppen<\/b> vorliegen, legen Sie erstens entsprechende Beziehungen zwischen den Tabellen an und aktivieren zweitens die Option <b>Mit referentieller Integrit&auml;t <\/b>der Beziehungen. All dies geschieht im Beziehungen-Fenster, dass Sie &uuml;ber den Men&uuml;eintrag <b>Extras|Beziehungen <\/b>(Access 2003 und &auml;lter) beziehungsweise den Ribboneintrag <b>Datenbanktools|Einblenden\/Ausblenden|Beziehungen <\/b>(Access 2007) &ouml;ffnen. Stellen Sie f&uuml;r beide Beziehungen au&szlig;erdem die Option <b>L&ouml;schweitergabe an verwandte Datens&auml;tze <\/b>ein. So gew&auml;hrleisten Sie, dass beim L&ouml;schen etwa eines Benutzers auch die damit verbundenen Datens&auml;tze aus der Verkn&uuml;pfungstabelle gel&ouml;scht werden (siehe Bild 11).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic011_opt.jpeg\" alt=\"pic011.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 11: Per referentieller Integrit&auml;t legen wir fest, dass die Tabelle tblBenutzerBenutzergruppen in ihren Fremdschl&uuml;sselfeldern nur g&uuml;ltige Werte haben kann.<\/span><\/b><\/p>\n<p><!--30percent--><\/p>\n<p><b>Verwalten von Benutzern und Benutzergruppen<\/b><\/p>\n<p>Die Access-Versionen 2003 und &auml;lter stellten jeweils zwei Dialoge zum Anlegen und zur Zuordnung von Benutzern und Benutzergruppen bereit &#8211; einen, mit dem Sie einen Benutzer anlegen oder ausw&auml;hlen und diesem die entsprechenden Benutzergruppen zuweisen k&ouml;nnen, und umgekehrt. Es ist sicher praktisch, die Zuordnung von Benutzern und Benutzergruppen sowohl aus Sicht der Benutzer als auch aus Sicht der Benutzergruppen verwalten zu k&ouml;nnen, daher werden wir ebenfalls gleich zwei Formulare f&uuml;r diesen Zweck anlegen. Das erste hei&szlig;t <b>frmBenutzerBenutzergruppen <\/b>und zeigt die Gruppenzugeh&ouml;rigkeit aus Sicht des Benutzers an. Es enth&auml;lt die folgenden Steuerelemente (siehe Bild 12):<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic012_opt.jpeg\" alt=\"pic012.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 12: Entwurf des Formulars zur Verwaltung von Benutzern und Benutzergruppen<\/span><\/b><\/p>\n<ul>\n<li class=\"aufz-hlung\"><b>cboBenutzer<\/b>: Kombinationsfeld zur Auswahl des zu bearbeitenden Benutzers<\/li>\n<li class=\"aufz-hlung\"><b>cmdBearbeiten<\/b>: Schaltfl&auml;che, die ein Formular zum Bearbeiten des aktuell ausgew&auml;hlten Benutzers &ouml;ffnet<\/li>\n<li class=\"aufz-hlung\"><b>cmdNeu<\/b>: Schaltfl&auml;che zum Anlegen eines neuen Benutzers<\/li>\n<li class=\"aufz-hlung\"><b>lstAusgewaehlt<\/b>: Listenfeld, das alle Gruppen des aktuellen Benutzers anzeigt<\/li>\n<li class=\"aufz-hlung\"><b>lstNichtAusgewaehlt<\/b>: Listenfeld, das alle &uuml;brigen Gruppen anzeigt<\/li>\n<li class=\"aufz-hlung\"><b>cmdEinzelnAuswaehlen<\/b>, <b>cmdEinzelnAbwaehlen<\/b>: Schaltfl&auml;chen zum Hinzuf&uuml;gen und Entfernen der aktuell ausgew&auml;hlten Gruppe zum Benutzer<\/li>\n<li class=\"aufz-hlung\"><b>cmdAlleAuswaehlen<\/b>, <b>cmdAlleAbwaehlen<\/b>: Schaltfl&auml;chen zum Hinzuf&uuml;gen und Entfernen aller Benutzergruppen<\/li>\n<li class=\"aufz-hlung\"><b>cmdOK<\/b>: Schaltfl&auml;che zum Schlie&szlig;en des Formulars<\/li>\n<\/ul>\n<p>Auch f&uuml;r dieses Formular stellen Sie wieder die Eigenschaften <b>Navigationsschaltfl&auml;chen<\/b>, <b>Datensatzmarkierer<\/b>, <b>Trennlinien <\/b>und <b>Bildlaufleisten <\/b>auf den Wert <b>Nein <\/b>ein.<\/p>\n<p><b>Auswahl des Benutzers<\/b><\/p>\n<p>Damit die Listenfelder <b>lstAusgewaehlt <\/b>und <b>lstNichtAusgewaehlt <\/b>die Benutzergruppen zu einem Benutzer anzeigen k&ouml;nnen, muss man zun&auml;chst den entsprechenden Benutzer mit dem Kombinationsfeld <b>cboBenutzer <\/b>ausw&auml;hlen k&ouml;nnen. Dazu legen wir als <b>Datensatzherkunft<\/b> die Abfrage aus Bild 13 fest.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic015_opt.jpeg\" alt=\"pic015.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 14: Das Kombinationsfeld cboBenutzer in Aktion<\/span><\/b><\/p>\n<p>Erstellen Sie diese als neue Abfrage und speichern Sie sie unter dem Namen <b>qryFrmBenutzerBenutzergruppenCboBenutzer<\/b>, um das Ziel dieser Abfrage zu verdeutlichen. Stellen Sie dann die Eigenschaft <b>Datensatzherkunft <\/b>des Kombinationsfeldes auf diesen Abfragenamen ein. Der folgende Ausdruck zeigt den Inhalt der drei enthaltenen Felder etwa in der Form <b>aminhorst (Andr&eacute; Minhorst) <\/b>im Kombinationsfeld an:<\/p>\n<pre>Benutzer: [Benutzername] &amp; &quot; (&quot; &amp; [Vorname] &amp; &quot; &quot; &amp; [Nachname] &amp; &quot;)&quot;<\/pre>\n<p>Damit jedoch nur der Inhalt der zweiten Spalte angezeigt und die erste Spalte der Datensatzherkunft ausgeblendet wird, m&uuml;ssen Sie noch die Eigenschaften <b>Spaltenanzahl <\/b>und <b>Spaltenbreiten <\/b>auf <b>2 <\/b>und <b>0cm <\/b>einstellen. In der Formularansicht sieht die Anzeige des Kombinationsfeldes nun wie in Bild 14 aus. Nun soll das Kombinationsfeld gleich beim &Ouml;ffnen des Formulars noch den ersten Eintrag anzeigen. Dazu legen Sie f&uuml;r die Ereigniseigenschaft <b>Beim Laden <\/b>des Formulars die folgende Ereignisprozedur an:<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic014_opt.jpeg\" alt=\"pic014.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 13: Diese Abfrage liefert die Datensatzherkunft f&uuml;r das Kombinationsfeld cboBenutzer.<\/span><\/b><\/p>\n<pre>Private Sub Form_Load()\r\n    Me!cboBenutzer = Me!cboBenutzer.ItemData(0)\r\n    End Sub<\/pre>\n<p>Anschlie&szlig;end wenden wir uns den beiden Listenfeldern zu, welche die zum ausgew&auml;hlten Benutzer geh&ouml;renden Benutzergruppen anzeigen sollen.<\/p>\n<p><b>Anzeige der zugeteilten Benutzergruppen<\/b><\/p>\n<p>Das erste Listenfeld namens <b>lstAusgewaehlt <\/b>soll alle Benutzergruppen anzeigen, die dem aktuell im Kombinationsfeld <b>cboBenutzer <\/b>ausgew&auml;hlten Benutzer zugewiesen sind. Das zweite enth&auml;lt die &uuml;brigen Benutzergruppen. Damit wir f&uuml;r die folgenden &auml;nderungen einige Testdaten haben, legen Sie zun&auml;chst ein paar Benutzergruppen an und weisen einige davon den vorhandenen Testbenutzern zu. Letzteres geschieht, indem Sie in die Tabelle <b>tblBenutzerBenutzergruppen <\/b>Kombinationen der vorhanden Werte der Felder <b>BenutzerID <\/b>und <b>BenutzergruppeID <\/b>der beiden Tabellen <b>tblBenutzer <\/b>und <b>tblBenutzergruppen <\/b>eintragen. Dies sieht dann wie in Bild 15 aus.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic013_opt.jpeg\" alt=\"pic013.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 15: Zuweisen von Benutzergruppen zu Benutzern in der Tabelle tblBenutzerBenutzergruppen<\/span><\/b><\/p>\n<p>Damit k&ouml;nnen wir uns an die Datensatzherk&uuml;nfte der beiden Listenfelder heranwagen. Das Listenfeld soll alle Datens&auml;tze der Tabelle <b>tblBenutzergruppen <\/b>anzeigen, die &uuml;ber die Tabelle <b>tblBenutzerBenutzergruppen<\/b> dem im Kombinationsfeld ausgew&auml;hlten Benutzer zugewiesen sind. Das Listenfeld soll die <b>BenutzerID <\/b>als gebundene, ausgeblendete Spalte und das Feld <b>Benutzer <\/b>als anzuzeigenden Wert enthalten. Dazu stellen Sie die Eigenschaften <b>Spaltenanzahl <\/b>und <b>Spaltenbreiten <\/b>wie schon oben beim Kombinationsfeld <b>cboBenutzer <\/b>auf die Werte <b>2 <\/b>und <b>0cm <\/b>ein.<\/p>\n<p>Da die anzuzeigenden Daten nach der Auswahl eines neuen Benutzers in <b>cboBenutzer <\/b>jeweils aktualisiert werden m&uuml;ssen, geh&ouml;rt die Zuweisung der entsprechenden SQL-Auswahlabfrage in eine VBA-Prozedur, die durch die Ereigniseigenschaft <b>Nach Aktualisierung <\/b>des Kombinationsfeld-Steuerelements ausgel&ouml;st wird. Dort k&ouml;nnen wir dann auslesen, welcher Benutzer gerade im Kombinationsfeld ausgew&auml;hlt ist, und eine entsprechende Datensatzherkunft f&uuml;r das Listenfeld <b>lstAusgewaehlt <\/b>zusammenstellen (s. Listing 2).<\/p>\n<p class=\"kastentabelleheader\">Listing 2: F&uuml;llen eines Listenfelds mit verkn&uuml;pften Benutzergruppen<\/p>\n<pre>Private Sub lstAusgewaehltFuellen()\r\n    Dim db As DAO.Database\r\n    Dim qdf As DAO.QueryDef\r\n    Dim prm As DAO.Parameter\r\n    Dim rst As DAO.Recordset\r\n    Dim lngBenutzerID As Long\r\n    Set db = CurrentDb\r\n    Set qdf = db.QueryDefs(&quot;qryFrmBenutzerBenutzergruppenLstAusgewaehlt&quot;)\r\n    lngBenutzerID = Nz(Me!cboBenutzer, 0)\r\n    Set prm = qdf.Parameters(&quot;prmBenutzerID&quot;)\r\n    prm.Value = lngBenutzerID\r\n    Set rst = qdf.OpenRecordset\r\n    If Not rst.EOF Then\r\n        rst.MoveLast\r\n    End If\r\n    Set Me!lstAusgewaehlt.Recordset = rst\r\n    End Sub<\/pre>\n<p>Als Basisabfrage dient die in Bild 16 dargestellte Abfrage <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt<\/b>. F&uuml;r das Feld <b>BenutzerID<\/b>, das nicht zur Ergebnismenge der Abfrage geh&ouml;rt, wurde ein Parameter namens <b>prmBenutzerID <\/b>festgelegt. Die folgende Prozedur erstellt zun&auml;chst eine Objektvariable namens <b>db <\/b>mit einem Verweis auf das aktuelle <b>Database<\/b>-Objekt. Diese liefert einen Verweis auf die soeben erstellte Abfrage. Nach der Ermittlung der <b>BenutzerID <\/b>des im Kombinationsfeld <b>cboBenutzer <\/b>ausgew&auml;hlten Benutzers erzeugt die Prozedur ein <b>Parameter<\/b>-Objekt zum F&uuml;llen des Parameters <b>prmBenutzerID <\/b>der gespeicherten Abfrage.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic016_opt.jpeg\" alt=\"pic016.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 16: Diese Abfrage dient als Basis f&uuml;r das F&uuml;llen des Listenfelds lstAusgewaehlt.<\/span><\/b><\/p>\n<p>Die folgende Anweisung weist diesem Parameter den Wert von <b>lngBenutzerID <\/b>zu, dann erzeugt die Prozedur ein <b>Recordset<\/b>-Objekt auf Basis der Abfrage mit dem angegebenen Parameterwert und weist dieses dem Listenfeld als <b>Recordset <\/b>zu. Das ist aber doch keine Ereignisprozedur Nein, ist es nicht: Es ist eine einfache Prozedur, deren Aufruf Sie erst noch in eine Ereignisprozedur einf&uuml;gen m&uuml;ssen &#8211; genau genommen sogar in mehrere. Das ist auch der Sinn, warum wir diese Funktion in eine eigene Prozedur gepackt haben: Das F&uuml;llen des Listenfeldes <b>lstAusgewaehlt <\/b>soll von mehreren Stellen aus geschehen, und zwar gleich beim &Ouml;ffnen des Formulars nach dem automatischen Ausw&auml;hlen des ersten Eintrags des Kombinationsfelds <b>cboBenutzer <\/b>und au&szlig;erdem durch die Ereignisprozedur, die durch das Ereignis <b>Nach Aktualisieren <\/b>des gleichen Kombinationfeldes ausgel&ouml;st wird. Die beiden Prozeduren sehen nun so aus:<\/p>\n<pre>Private Sub Form_Load()\r\n    Me!cboBenutzer = Me!cboBenutzer.ItemData(0)\r\n    Call lstAusgewaehltFuellen\r\n    End Sub\r\nPrivate Sub cboBenutzer_AfterUpdate()\r\n    Call lstAusgewaehltFuellen\r\n    End Sub<\/pre>\n<p>Im gleichen Zuge soll auch noch das zweite Listenfeld mit Daten gef&uuml;llt werden. Dazu ben&ouml;tigen wir eine Abfrage, die alle Datens&auml;tze der Tabelle <b>tblBenutzergruppen <\/b>liefert, die nicht in der Datensatzherkunft des Listenfeldes <b>lstAusgewaehlt <\/b>enthalten sind &#8211; also alle, die &uuml;brig bleiben. Die Definition dieser Abfrage k&ouml;nnen Einsteiger im ersten Moment sicher nicht herleiten, daher eine ausf&uuml;hrliche Erl&auml;uterung. Die Basis der Abfrage besteht ja bereits: Es handelt sich um die Abfrage, welche alle im linken Listenfeld angezeigten Eintr&auml;ge liefert. Wir gehen dies nun in vier Schritten an:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Erstellen Sie eine Abfrage namens <b>qryFrmBenutzerBenutzergruppenLstNichtAusgewaehlt <\/b>und f&uuml;gen Sie die Abfrage <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt <\/b>zum Entwurf dieser Abfrage hinzu.<\/li>\n<li class=\"aufz-hlung\">F&uuml;gen Sie die Tabelle <b>tblBenutzergruppen <\/b>zur Abfrage hinzu. Es wird automatisch eine Beziehung zwischen dem Feld <b>BenutzergruppeID <\/b>der beiden Datenherk&uuml;nfte erstellt. Die Abfrage zeigt nun, wenn Sie alle Felder der Tabelle <b>tblBenutzergruppen <\/b>zum Entwurfsraster hinzuf&uuml;gen, genau die gleichen Daten wie die Abfrage <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt <\/b>an.<\/li>\n<li class=\"aufz-hlung\">Nun sorgen Sie zun&auml;chst daf&uuml;r, dass die Abfrage alle Datens&auml;tze der Tabelle <b>tblBenutzergruppen <\/b>anzeigt. Dazu klicken Sie doppelt auf den Beziehungspfeil und stellen in den Beziehungseigenschaften die Option <b>Beinhaltet ALLE Datens&auml;tze aus &#8220;&#8220;tblBenutzergruppen&#8220;&#8220; &#8230; <\/b>ein (siehe Bild 17). Unabh&auml;ngig davon, ob es zu einem Datensatz aus <b>tblBenutzergruppen <\/b>einen Datensatz in <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt <\/b>gibt, werden alle Datens&auml;tze aus <b>tblBenutzergruppen <\/b>angezeigt.<\/li>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic018_opt.jpeg\" alt=\"pic018.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 17: Mit dieser Einstellung zeigt die Abfrage alle Datens&auml;tze der Tabelle tblBenutzergruppen an.<\/span><\/b><\/p>\n<li class=\"aufz-hlung\">Wir wollen aber nur diejenigen Datens&auml;tze, die nicht in <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt <\/b>enthalten sind. Also f&uuml;gen wir das Feld <b>BenutzergruppeID <\/b>dieser Abfrage zum Entwurfsraster hinzu. Dadurch wird in dieser Spalte ein Wert angezeigt, wenn dieser Datensatz in <b>qryFrmBenutzerBenutzergruppenLstAusgewaehlt <\/b>vorliegt, und es wird ein <b>Null<\/b>-Wert angezeigt, wenn diese Benutzergruppe nicht dem ausgew&auml;hlten Benutzer zugeordnet ist. Der n&auml;chste Schritt ist logisch: F&uuml;gen Sie f&uuml;r das soeben hinzugef&uuml;gte Feld ein Kriterium mit dem Inhalt <b>Ist Null <\/b>hinzu. So liefert die Abfrage nur Datens&auml;tze, die nicht schon im anderen Listenfeld angezeigt werden.<\/li>\n<\/ul>\n<p>Bild 18 zeigt die Abfrage in der Entwurfsansicht. Die Prozedur zum &Ouml;ffnen eines Recordsets auf Basis dieser Abfrage und zum Zuweisen dieser Abfrage zum Listenfeld <b>lstNichtAusgewaehlt <\/b>hei&szlig;t <b>lstNichtAusgewaehltFuellen <\/b>und sieht bis auf Details wie die Prozedur <b>lstAusgewaehltFuellen <\/b>aus. Sie finden diese Prozedur ebenfalls im Klassenmodul des Formulars <b>frmBenutzerBenutzergruppen<\/b>. Nachdem wir nun nicht nur eines, sondern zwei Listenfelder f&uuml;llen m&uuml;ssen, m&uuml;ssen wir nat&uuml;rlich auch unsere Ereignisprozeduren &auml;ndern, die beim Laden des Formulars und beim Ausw&auml;hlen eines neuen Benutzers aus dem Kombinationsfeldes ausgel&ouml;st werden. Diese sehen nun so aus:<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic017_opt.jpeg\" alt=\"pic017.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 18: Datensatzherkunft des Listenfeldes zur Anzeige aller nicht ausgew&auml;hlter Benutzergruppen eines Benutzers<\/span><\/b><\/p>\n<pre>Private Sub Form_Load()\r\n    Me!cboBenutzer = Me!cboBenutzer.ItemData(0)\r\n    Call lstAusgewaehltFuellen\r\n    Call lstNichtAusgewaehltFuellen\r\n    End Sub\r\nPrivate Sub cboBenutzer_AfterUpdate()\r\n    Call lstAusgewaehltFuellen\r\n    Call lstNichtAusgewaehltFuellen\r\n    End Sub<\/pre>\n<p><b>Benutzergruppen zuweisen<\/b><\/p>\n<p>Das Zuweisen der Benutzergruppen erfolgt entweder durch einen Doppelklick auf einen der Eintr&auml;ge im Listenfeld <b>lstNichtAusgewaehlt <\/b>oder durch Ausw&auml;hlen eines der Eintr&auml;ge und anschlie&szlig;endes Bet&auml;tigen der Schaltfl&auml;che <b>cmdEinzelnAuswaehlen <\/b>zum Hinzuf&uuml;gen einer einzelnen Benutzergruppe. Zum Hinzuf&uuml;gen aller Benutzergruppen gleichzeitig soll ein Klick auf die Schaltfl&auml;che <b>cmdAlleAuswaehlen <\/b>dienen.<\/p>\n<p>Die durch einen Doppelklick auf einen Eintrag des Listenfelds <b>lstNichtAusgewaehlt <\/b>ausgel&ouml;ste Prozedur ruft eine weitere Prozedur namens <b>EinzelnAuswaehlen <\/b>auf. Diese bezieht ihre Daseinsberechtigung wiederum daher, dass die enthaltene Funktion von mehreren Stellen aus aufgerufen werden soll:<\/p>\n<pre>Private Sub lstNichtAusgewaehlt_DblClick(Cancel _\r\n    As Integer)\r\n    Call EinzelnAuswaehlen\r\n    End Sub<\/pre>\n<p>Diese Prozedur sieht wie in Listing 3 aus und deklariert zun&auml;chst ein <b>Database<\/b>-Objekt sowie zwei <b>Long<\/b>-Variablen. Bevor sie richtig loslegt, pr&uuml;ft sie, ob der Benutzer &uuml;berhaupt einen Eintrag im Listenfeld markiert hat. Dabei ist die Eigenschaft <b>Count <\/b>der Auflistung der markierten Eintr&auml;ge, <b>ItemsSelected<\/b>, hilfreich.<\/p>\n<p class=\"kastentabelleheader\">Listing 3: Hinzuf&uuml;gen einer Benutzergruppe zum aktuellen Benutzer<\/p>\n<pre>Private Sub EinzelnAuswaehlen()\r\n    Dim db As DAO.Database\r\n    Dim lngBenutzerID As Long\r\n    Dim lngBenutzergruppeID As Long\r\n    If Me!lstNichtAusgewaehlt.ItemsSelected.Count = 1 Then\r\n        Set db = CurrentDb\r\n        lngBenutzerID = Nz(Me!cboBenutzer, 0)\r\n        lngBenutzergruppeID = Me!lstNichtAusgewaehlt\r\n        db.Execute &quot;INSERT INTO tblBenutzerBenutzergruppen(BenutzerID, BenutzergruppeID) VALUES(&quot; _\r\n        &amp; lngBenutzerID &amp; &quot;, &quot; &amp; lngBenutzergruppeID &amp; &quot;)&quot;, dbFailOnError\r\n        Call lstAusgewaehltFuellen\r\n        Call lstNichtAusgewaehltFuellen\r\n    End If\r\n    End Sub<\/pre>\n<p>Weist diese Eigenschaft den Wert <b>1 <\/b>auf, dann ist ein Listenfeldeintrag markiert und der Inhalt der <b>If&#8230;Then<\/b>-Bedingung wird ausgef&uuml;hrt. Die Variable <b>db <\/b>wird mit einem Verweis auf das aktuelle <b>Database<\/b>-Objekt gef&uuml;llt und die beiden <b>Long<\/b>-Variablen <b>lngBenutzerID <\/b>und <b>lngBenutzergruppeID <\/b>erhalten die Prim&auml;rschl&uuml;sselwerte des betroffenen Benutzers (aus <b>cboBenutzer<\/b>) und der hinzuzuf&uuml;genden Benutzergruppe (aus <b>lstNichtAusgewaehlt<\/b>) als Wert.<\/p>\n<p>Schlie&szlig;lich f&uuml;gt eine <b>INSERT INTO<\/b>-Aktionsabfrage einen neuen Datensatz zur Tabelle <b>tblBenutzerBenutzergruppen <\/b>hinzu, der die Werte aus <b>lngBenutzerID <\/b>und <b>lngBenutzergruppeID <\/b>f&uuml;r die Felder <b>BenutzerID <\/b>und <b>BenutzergruppeID <\/b>erh&auml;lt.<\/p>\n<p>Zu guter Letzt m&uuml;ssen die beiden Listenfelder noch aktualisiert werden, damit der Benutzer auch etwas vom just angelegten Datensatz in der Tabelle <b>tblBenutzerBenutzergruppe <\/b>mitbekommt &#8211; und dies erledigen die bereits bekannten Prozeduren <b>lstAusgewaehltFuellen <\/b>und <b>lstNichtAusgewaehltFuellen<\/b>. Die Prozedur <b>EinzelnAuswaehlen <\/b>wird auch aufgerufen, wenn der Benutzer auf die Schaltfl&auml;che <b>cmdEinzelnAuswaehlen <\/b>klickt:<\/p>\n<pre>Private Sub cmdEinzelnAuswaehlen_Click()\r\n    Call EinzelnAuswaehlen\r\n    End Sub<\/pre>\n<p>Wenn ein Benutzer mit allen m&ouml;glichen Berechtigungen ausgestattet werden soll, k&ouml;nnen Sie diesem nat&uuml;rlich auch gleich alle Benutzergruppen zuweisen. Den Start macht ein Klick auf die Schaltfl&auml;che <b>cmdAlleAuswaehlen<\/b>, was diese Ereignisprozedur ausl&ouml;st:<\/p>\n<pre>Private Sub cmdAlleAuswaehlen_Click()\r\n    Call AlleAuswaehlen\r\n    End Sub<\/pre>\n<p>Die einzige Anweisung dieser Prozedur ruft eine weitere Prozedur namens <b>AlleAuswaehlen <\/b>auf. Deren Inhalt h&auml;tten wir zwar auch gleich in die Ereignisprozedur <b>cmdAlleAuswaehlen_Click <\/b>schreiben k&ouml;nnen, aber wir wollten an dieser Stelle konsequent alle Funktionen zum Aus- und Abw&auml;hlen der Benutzergruppen eines Benutzers in eigene Prozeduren auslagern. Die Prozedur <b>AlleAuswaehlen <\/b>finden Sie in Listing 4.<\/p>\n<p class=\"kastentabelleheader\">Listing 4: Diese Prozedur weist einem Benutzer alle verf&uuml;gbaren Benutzergruppen zu.<\/p>\n<pre>Private Sub AlleAuswaehlen()\r\nDim db As DAO.Database\r\nDim lngBenutzerID As Long\r\nSet db = CurrentDb\r\nlngBenutzerID = Nz(Me!cboBenutzer, 0)\r\ndb.Execute &quot;DELETE FROM tblBenutzerBenutzergruppen WHERE BenutzerID = &quot; _\r\n&amp; lngBenutzerID, dbFailOnError\r\ndb.Execute &quot;INSERT INTO tblBenutzerBenutzergruppen SELECT &quot; &amp; lngBenutzerID _\r\n&amp; &quot; AS BenutzerID, BenutzergruppeID FROM tblBenutzergruppen&quot;, dbFailOnError\r\nCall lstAusgewaehltFuellen\r\nCall lstNichtAusgewaehltFuellen\r\nEnd Sub<\/pre>\n<p>Sie h&auml;lt sich nicht damit auf, zu pr&uuml;fen, welche Benutzergruppen dem aktuellen Benutzer bereits zugewiesen sind und welche nicht, sondern entfernt schlicht alle zugewiesenen Benutzergruppen und f&uuml;gt dann alle hinzu. Dazu liest die Prozedur ebenfalls zun&auml;chst die ID des aktuell im Kombinationsfeld ausgew&auml;hlten Benutzers aus und speichert diese in einer <b>Long<\/b>-Variablen. Danach l&ouml;scht eine <b>DELETE<\/b>-Aktionsabfrage alle Datens&auml;tze der Tabelle <b>tblBenutzerBenutzergruppen<\/b>, deren Feld <b>BenutzerID <\/b>die ID des aktuellen Benutzers enth&auml;lt. Eine <b>INSERT INTO<\/b>-Abfrage f&uuml;gt dann f&uuml;r jeden Datensatz der Tabelle <b>tblBenutzergruppen <\/b>einen neuen Datensatz zur Tabelle <b>tblBenutzerBenutzergruppen <\/b>hinzu, wobei das Feld <b>BenutzerID <\/b>jeweils mit der ID aus der Variablen <b>lngBenutzerID <\/b>und das Feld <b>BenutzergruppeID <\/b>mit dem entsprechenden Datensatz der Tabelle <b>tblBenutzergruppen <\/b>gef&uuml;llt wird. Auch hier findet zum Abschluss die Aktualisierung der beiden Listenfelder statt.<\/p>\n<p><b>Benutzergruppen entfernen<\/b><\/p>\n<p>Das Entfernen einer einzelnen oder aller aktuell ausgew&auml;hlten Benutzergruppen eines Benutzers geht noch einfacher. Eine einzelne Benutzergruppe entfernt beispielsweise ein Doppelklick auf einen Eintrag des Listenfelds <b>lstAusgewaehlt <\/b>oder das Ausw&auml;hlen eines Eintrags und ein anschlie&szlig;ender Klick auf die Schaltfl&auml;che <b>cmdEinzelnAbwaehlen<\/b>. Die entsprechenden Ereignisprozeduren sehen so aus:<\/p>\n<pre>Private Sub cmdEinzelnAbwaehlen_Click()\r\n    Call EinzelnAbwaehlen\r\n    End Sub\r\nPrivate Sub lstAusgewaehlt_DblClick(Cancel As Integer)\r\n    Call EinzelnAbwaehlen\r\n    End Sub<\/pre>\n<p>Beide rufen die Prozedur <b>EinzelnAbwaehlen <\/b>auf, die Sie in Listing 5 finden. Die Prozedur arbeitet &auml;hnlich wie die Prozedur <b>EinzelnAuswaehlen<\/b>, f&uuml;gt aber keinen Datensatz zur Tabelle <b>tblBenutzerBenutzergruppen <\/b>hinzu, sondern entfernt stattdessen einen Eintrag. Die dazu notwendige <b>DELETE<\/b>-Aktionsabfrage sucht sich dabei den Datensatz heraus, dessen Felder <b>BenutzerID <\/b>und <b>BenutzergruppeID <\/b>genau die in den beiden <b>Long<\/b>-Variablen gespeicherten Werte aufweisen, und l&ouml;scht diesen. Fehlt noch das Abw&auml;hlen aller dem aktuellen Benutzer zugewiesenen Benutzergruppen, was durch einen Klick auf die Schaltfl&auml;che <b>cmdAlleAbwaehlen <\/b>geschieht:<\/p>\n<p class=\"kastentabelleheader\">Listing 7: Diese Prozedur &ouml;ffnet das Formular zum Anlegen eines neuen Benutzers und aktualisiert anschlie&szlig;end das Kombinationsfeld zur Anzeige des aktuellen Benutzers.<\/p>\n<p class=\"kastentabelleheader\">Listing 5: Diese Prozedur l&ouml;scht den aktuell markierten Eintrag des Listenfeldes lstAusgewaehlt.<\/p>\n<pre>Private Sub EinzelnAbwaehlen()\r\n    Dim db As DAO.Database\r\n    Dim lngBenutzerID As Long\r\n    Dim lngBenutzergruppeID As Long\r\n    If Me!lstAusgewaehlt.ItemsSelected.Count = 1 Then\r\n        Set db = CurrentDb\r\n        lngBenutzerID = Nz(Me!cboBenutzer, 0)\r\n        lngBenutzergruppeID = Me!lstAusgewaehlt\r\n        db.Execute &quot;DELETE FROM tblBenutzerBenutzergruppen WHERE BenutzerID = &quot; &amp; lngBenutzerID _\r\n        &amp; &quot; AND BenutzergruppeID = &quot; &amp; lngBenutzergruppeID, dbFailOnError\r\n        Call lstAusgewaehltFuellen\r\n        Call lstNichtAusgewaehltFuellen\r\n    End If\r\n    End Sub\r\nPrivate Sub cmdAlleAbwaehlen_Click()\r\n    Call AlleAbwaehlen\r\n    End Sub<\/pre>\n<p>Die hier aufgerufene Prozedur <b>AlleAbwaehlen <\/b>hat leichtes Spiel: Sie braucht einfach nur mit einer entsprechenden <b>DELETE<\/b>-Anweisung alle Eintr&auml;ge der Tabelle <b>tblBenutzerBenutzergruppen<\/b> zu l&ouml;schen, deren Feld <b>BenutzerID<\/b> den im Kombinationsfeld <b>cboBenutzer<\/b> ausgew&auml;hlten Wert aufweist (s. Listing 6).<\/p>\n<p class=\"kastentabelleheader\">Listing 6: L&ouml;schen aller einem Benutzer zugeordneten Benutzergruppen<\/p>\n<pre>Private Sub AlleAbwaehlen()\r\nDim db As DAO.Database\r\nDim lngBenutzerID As Long\r\nSet db = CurrentDb\r\nlngBenutzerID = Nz(Me!cboBenutzer, 0)\r\ndb.Execute &quot;DELETE FROM tblBenutzerBenutzergruppen WHERE BenutzerID = &quot; &amp; lngBenutzerID, _\r\ndbFailOnError\r\nCall lstAusgewaehltFuellen\r\nCall lstNichtAusgewaehltFuellen\r\nEnd Sub<\/pre>\n<p><b>Benutzer hinzuf&uuml;gen und bearbeiten<\/b><\/p>\n<p>F&uuml;r die Bearbeitung der in der Tabelle <b>tblBenutzer <\/b>gespeicherten Datens&auml;tze legen wir ein Formular namens <b>frmBenutzerDetail <\/b>an. Dieses besitzt die Tabelle <b>tblBenutzer <\/b>als <b>Datenherkunft <\/b>und soll in der Formularansicht einfach alle in dieser Tabelle enthaltenen Felder anzeigen &#8211; mit Ausnahme des Prim&auml;rschl&uuml;sselfeldes <b>BenutzerID<\/b>, weil dies f&uuml;r den Benutzer v&ouml;llig uninteressant ist.<\/p>\n<p>Stellen Sie die Eigenschaften <b>Datensatzmarkierer<\/b>, <b>Navigationsschaltfl&auml;chen<\/b>, <b>Trennlinien <\/b>und <b>Bildlaufleisten <\/b>auf <b>Nein <\/b>und die Eigenschaft <b>Zentriert anzeigen <\/b>auf <b>Ja <\/b>ein.<\/p>\n<p>F&uuml;r das Feld <b>Kennwort <\/b>legen Sie als <b>Eingabeformat <\/b>den Eintrag <b>Kennwort <\/b>fest (siehe Bild 19). Schlie&szlig;lich stellen Sie die Eigenschaften <b>Mit Systemfeldmen&uuml; <\/b>und <b>Schlie&szlig;en-Schaltfl&auml;che <\/b>auf den Wert <b>Nein <\/b>und <b>MinMax-Schaltfl&auml;chen <\/b>auf <b>Keine <\/b>ein. So stellen Sie sicher, dass der Benutzer das Formular nur &uuml;ber die nun zu erstellenden Schaltfl&auml;chen verlassen kann.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic019_opt.jpeg\" alt=\"pic019.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 19: Das Formular frmBenutzerDetail zeigt die Eigenschaften eines Benutzers an.<\/span><\/b><\/p>\n<p>Diese beiden Schaltfl&auml;chen sollen <b>cmdOK <\/b>und <b>cmdAbbrechen<\/b> hei&szlig;en. Die Schaltfl&auml;che <b>cmdAbbrechen <\/b>soll beim Anklicken schlicht die folgende Ereignisprozedur ausl&ouml;sen:<\/p>\n<pre>Private Sub cmdAbbrechen_Click()\r\n    Me.Undo\r\n    DoCmd.Close acForm, Me.Name\r\n    End Sub<\/pre>\n<p>Dadurch werden die &auml;nderungen verworfen und das Formular wird geschlossen. Die Prozedur der <b>OK<\/b>-Schaltfl&auml;che sieht schon komplizierter aus:<\/p>\n<pre>Private Sub cmdOK_Click()\r\n    Select Case Me.DefaultEditing\r\n    Case 1 ''''Neu\r\n    Me.Visible = False\r\n    Case 2 ''''Bearbeiten\r\n    DoCmd.Close acForm, Me.Name\r\n    End Select\r\n    End Sub<\/pre>\n<p>Was ist <b>DefaultEditing<\/b> und wof&uuml;r brauchen wir verschiedene Aktionen beim Schlie&szlig;en <b>DefaultEditing <\/b>ist eine verborgene Eigenschaft (das hei&szlig;t, sie wird nicht mehr offiziell unterst&uuml;tzt, ist aber aus Kompatibilit&auml;tsgr&uuml;nden noch vorhanden). Sie liefert einen Zahlenwert zur&uuml;ck, der festlegt, in welchem Modus das Formular ge&ouml;ffnet wurde. Ist der Wert <b>1<\/b>, wurde das Formular mit einem neuen, leeren Datensatz ge&ouml;ffnet, beim Wert <b>2 <\/b>wird ein bestehender Wert angezeigt. In beiden F&auml;llen ist das Bearbeiten m&ouml;glich. F&uuml;r unseren Fall ist das wichtig, weil wir das Formular von zwei Stellen aus f&uuml;r die beiden unterschiedlichen Bearbeitungsmodi aufrufen &#8211; und damit landen wir wieder beim Formular <b>frmBenutzerBenutzergruppen<\/b>.<\/p>\n<p>Dieses enth&auml;lt ja, wie auch in Bild 19 gut zu erkennen, zwei Schaltfl&auml;chen hinter dem Kombinationsfeld <b>cboBenutzer<\/b>. Wenn Sie auf die Schaltfl&auml;che mit den drei Punkten (&#8230;) klicken, soll das Formular <b>frmBenutzerDetail <\/b>erscheinen und den aktuell im Kombinationsfeld ausgew&auml;hlten Benutzer zum Bearbeiten anzeigen. Das ist schnell erledigt, und zwar mit der ersten Anweisung der Prozedur, die durch die Ereigniseigenschaft <b>Beim Klicken <\/b>dieser Schaltfl&auml;che ausgel&ouml;st wird:<\/p>\n<pre>Private Sub cmdBearbeiten_Click()\r\n    DoCmd.OpenForm &quot;frmBenutzerDetail&quot;, _\r\n    WindowMOde:=acDialog, _\r\n    DataMode:=acFormEdit, _\r\n    WhereCondition:=&quot;BenutzerID = &quot; _\r\n    &amp; Me!cboBenutzer\r\n    Me!cboBenutzer.Requery\r\n    End Sub<\/pre>\n<p>Die Verwendung des Parameters <b>acFormEdit <\/b>f&uuml;hrt dazu, dass das Formular <b>frmBenutzerDetail <\/b>beim &Ouml;ffnen den mit dem Parameter <b>WhereCondition <\/b>angegebenen Datensatz zum Bearbeiten anzeigt und dass seine Eigenschaft <b>DefaultEditing <\/b>den Wert <b>2 <\/b>annimmt.<\/p>\n<p>Der Parameter <b>WindowMode <\/b>sorgt mit dem Wert <b>acDialog <\/b>&uuml;berdies daf&uuml;r, dass Access das Formular <b>frmBenutzerDetail <\/b>als modalen Dialog &ouml;ffnet &#8211; das stellt erstens sicher, dass der Benutzer nicht auf andere Elemente der Benutzeroberfl&auml;che zugreifen kann, und zweitens wird der aufrufende Code, hier die <b>DoCmd<\/b>-Anweisung, unterbrochen, bis das Formular geschlossen oder unsichtbar gemacht wird. In diesem Fall ist das hilfreich, weil wir so nach dem Schlie&szlig;en des Formulars <b>frmBenutzerDetails <\/b>noch eine Anweisung zum Aktualisieren des Inhalts des Kombinationsfeldes loslassen k&ouml;nnen &#8211; dadurch werden eventuelle &auml;nderungen an den Benutzereigenschaften, die im Kombinationsfeld angezeigt werden, gleich in der neuen Fassung dargestellt.<\/p>\n<p><b>Neuen Benutzer anlegen<\/b><\/p>\n<p>Das Formular <b>frmBenutzerDetail <\/b>soll auch dann ge&ouml;ffnet werden, wenn der Benutzer auf die Schaltfl&auml;che <b>cmdNeu <\/b>des Formulars <b>frmBenutzerBenutzergruppen <\/b>klickt. Beim Anlegen eines neuen Benutzers soll dieser gleich im Kombinationsfeld ausgew&auml;hlt werden &#8211; wozu sollte man sonst einen neuen Benutzer anlegen Schauen wir uns also die Ereignisprozedur an, die durch das Ereignis <b>Beim Klicken <\/b>der Schaltfl&auml;che <b>cmdNeu <\/b>ausgel&ouml;st wird (s. Listing 7). Diese Prozedur &ouml;ffnet zun&auml;chst das Formular, und zwar diesmal mit dem Wert <b>acFormAdd <\/b>f&uuml;r den Parameter <b>DataMode<\/b>. Dies f&uuml;hrt dazu, dass das Formular einen neuen, leeren Datensatz anzeigt und der Wert der Eigenschaft <b>DefaultEditing <\/b>auf <b>1 <\/b>eingestellt wird. Durch das &Ouml;ffnen als modaler Dialog wird die Prozedur nun unterbrochen, bis der Benutzer eine der beiden Schaltfl&auml;chen <b>cmdOK <\/b>oder <b>cmdAbbrechen <\/b>des Formulars <b>frmBenutzerDetail <\/b>bet&auml;tigt. Die <b>Abbrechen<\/b>-Schaltfl&auml;che schlie&szlig;t das Formular einfach. Die folgende Anweisung der aufrufenden Prozedur pr&uuml;ft nun mit der benutzerdefinierten Funktion <b>IstFormularGeoeffnet<\/b>, ob das Formular <b>frmBenutzerDetail<\/b> noch ge&ouml;ffnet ist. Das ist hier nicht der Fall, also werden die in der <b>If&#8230;Then<\/b>-Bedingung enthaltenen Anweisungen diesmal nicht ausgef&uuml;hrt.<\/p>\n<pre>Private Sub cmdNeu_Click()\r\n    Dim lngBenutzerID As Long\r\n    DoCmd.OpenForm &quot;frmBenutzerDetail&quot;, WindowMOde:=acDialog, DataMode:=acFormAdd\r\n    If IstFormularGeoeffnet(&quot;frmBenutzerDetail&quot;) Then\r\n        lngBenutzerID = Forms!frmBenutzerDetail!BenutzerID\r\n        DoCmd.Close acForm, &quot;frmBenutzerDetail&quot;\r\n        Me!cboBenutzer = lngBenutzerID\r\n        Me!cboBenutzer.Requery\r\n        Call lstAusgewaehltFuellen\r\n        Call lstNichtAusgewaehltFuellen\r\n    End If\r\n    End Sub<\/pre>\n<p>Anders verh&auml;lt es sich, wenn der Benutzer tats&auml;chlich einen neuen Benutzer angelegt und auf die <b>OK<\/b>-Schaltfl&auml;che von <b>frmBenutzerDetail <\/b>geklickt hat. Dann liefert die Funktion <b>IstFormularGeoeffnet<\/b>, die Sie &uuml;brigens im Modul <b>mdlTools <\/b>der Beispieldatenbank finden, den Wert <b>True <\/b>zur&uuml;ck und die <b>If&#8230;Then<\/b>-Bedingung f&uuml;hrt die enthaltenen Anweisungen aus. Dabei greift sie zun&auml;chst auf das noch ge&ouml;ffnete Formular <b>frmBenutzerDetail <\/b>zu und liest den Wert des Prim&auml;rschl&uuml;sselfeldes <b>BenutzerID<\/b>, das zwar nicht im Formular angezeigt wird, aber dennoch vorhanden ist, in die <b>Long<\/b>-Variable <b>lngBenutzerID <\/b>ein. Nachdem dies geschehen ist, haben wir alle ben&ouml;tigten Informationen und k&ouml;nnen das Formular, das ja nur unsichtbar gemacht wurde, endg&uuml;ltig schlie&szlig;en. Das ist wichtig, denn wir wollen im Folgenden das Kombinationsfeld, das die Benutzer anzeigt, dazu bringen, den neuen Benutzer auszuw&auml;hlen. Hierf&uuml;r sind zwei Schritte n&ouml;tig:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Die Datensatzherkunft des Kombinationsfeldes muss aktualisiert werden. Dies erledigt die <b>Requery<\/b>-Methode dieses Steuerelements.<\/li>\n<li class=\"aufz-hlung\">Das Kombinationsfeld muss auf die <b>BenutzerID <\/b>des neu hinzugef&uuml;gten Benutzers eingestellt werden. Das geschieht einfach durch Zuweisen des daf&uuml;r in der Variablen <b>lngBenutzerID <\/b>gespeicherten Werts an das Kombinationsfeld.<\/li>\n<\/ul>\n<p>Wof&uuml;r aber nun mussten wir die <b>BenutzerID <\/b>in einer Variablen speichern und das Formular <b>frmBenutzerDetail <\/b>vorher schlie&szlig;en Ganz einfach: Die Datensatzherkunft des Kombinationsfeldes kann den neuen Benutzer nur dann aufnehmen, wenn dieser auch in der zugrunde liegenden Tabelle <b>tblBenutzer<\/b> gespeichert ist. Und dies geschieht zum Beispiel dann, wenn man das Formular, mit dem der Benutzer angelegt wurde, schlie&szlig;t. Schlie&szlig;lich m&uuml;ssen wir noch daf&uuml;r sorgen, dass die Listenfelder mit den Benutzergruppen im neuen Benutzerdatensatz entsprechend aktualisiert werden, und rufen daf&uuml;r die beiden Prozeduren <b>lstAusgewaehltFuellen <\/b>und <b>lstNichtAusgewaehltFuellen <\/b>auf.<\/p>\n<p><b>Berechtigungen verwalten<\/b><\/p>\n<p>Wenden wir uns nun einem wichtigen Thema dieser L&ouml;sung zu: den Berechtigungen.<\/p>\n<p>Hier gibt es mehrere Entscheidungen, die Sie vor der Programmierung und der Erstellung des Datenmodells treffen m&uuml;ssen:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Sollen Berechtigungen nur f&uuml;r Benutzer, nur f&uuml;r Benutzergruppen oder f&uuml;r beide festgelegt werden k&ouml;nnen Und wenn f&uuml;r beide: Welche Berechtigung hat dann Priorit&auml;t beziehungsweise wird automatisch die h&ouml;here Berechtigung verwendet<\/li>\n<li class=\"aufz-hlung\">Sollen Berechtigungen f&uuml;r einzelne Objekte oder Bereiche einzeln vergeben werden oder gibt es je Benutzer\/Benutzergruppe nur eine Einstufung in die verf&uuml;gbaren Berechtigungsstufen, die dann f&uuml;r alle Objekte und Elemente gilt<\/li>\n<li class=\"aufz-hlung\">Sollen die Berechtigungen aufeinander aufbauen, sodass man nur die jeweils h&ouml;chste Stufe festlegen muss, oder gibt es verschiedene Berechtigungen etwa zum Lesen, Schreiben oder L&ouml;schen, die unabh&auml;ngig voneinander vergeben werden k&ouml;nnen<\/li>\n<\/ul>\n<p>Diese Themen schauen wir uns in den folgenden Abschnitten an.<\/p>\n<p><b>Benutzer und Benutzergruppen<\/b><\/p>\n<p>Die Einteilung in Benutzergruppen haben wir ja vorgenommen, damit man Standards&auml;tze von Berechtigungen festlegen und diese einem Benutzer &uuml;ber die Benutzergruppe zuweisen kann. Die einfachste Methode ist, tats&auml;chlich nur Berechtigungen auf Benutzergruppenebene zu vergeben und nicht auf Benutzerebene. Au&szlig;erdem deckt diese Regelung auch Sonderf&auml;lle ab, in denen ein einziger Benutzer ein spezielles Recht erhalten soll. Sie m&uuml;ssen dann nur eine neue Gruppe mit den entsprechenden Berechtigungen anlegen, der Sie nur den fraglichen Benutzer zuweisen.<\/p>\n<p>Dies setzt nat&uuml;rlich voraus, dass ein Benutzer auch mehr als einer Gruppe zugeteilt werden kann, was durch die bisherige Fassung der Beispieldatenbank aber m&ouml;glich ist.<\/p>\n<p>Unabh&auml;ngig davon, ob Sie Berechtigungen auf Benutzer- und\/oder Benutzergruppenebene vergeben, sollten Sie festlegen, dass ein Benutzer, der in mehreren Benutzergruppen vertreten ist, immer die h&ouml;chste der ihm zugewiesenen Berechtigungen erh&auml;lt. Wir gehen in den folgenden Schritten davon aus, dass nur Berechtigungen f&uuml;r Benutzergruppen vergeben werden.<\/p>\n<p><b>Globale oder objektbezogene Berechtigungen<\/b><\/p>\n<p>Unter Access 2003 und &auml;lter konnten Sie f&uuml;r jeden einzelnen Benutzer und auch f&uuml;r die Benutzergruppen die Berechtigungen f&uuml;r jedes Element der Datenbank festlegen, also zum Beispiel f&uuml;r die einzelnen Tabellen, Abfragen, Formulare, Berichte und auch f&uuml;r allgemeine Belange wie etwa der Verwaltung der Datenbank. Dies ist eine Variante. Alternativ legen Sie einfach eine Berechtigungsstufe f&uuml;r eine bestimmte Benutzergruppe fest. Diese wird etwa beim &Ouml;ffnen von Formularen oder beim Ausf&uuml;hren von Funktionen abgefragt und f&uuml;hrt dazu, dass das &Ouml;ffnen des Formulars oder das Ausf&uuml;hren der Funktion erlaubt wird oder auch nicht. Dies soll die Variante sein, die wir weiter unten beschreiben.<\/p>\n<p><b>Abh&auml;ngige oder unabh&auml;ngige Berechtigungen<\/b><\/p>\n<p>Ein Beispiel f&uuml;r aufeinander aufbauende Berechtigungen ist folgendes:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Kein Zugriff<\/li>\n<li class=\"aufz-hlung\">Lesender Zugriff<\/li>\n<li class=\"aufz-hlung\">Lesender und schreibender Zugriff<\/li>\n<li class=\"aufz-hlung\">Lesender und schreibender Zugriff und L&ouml;schberechtigung<\/li>\n<\/ul>\n<p>Die einzelnen Berechtigungen k&ouml;nnen Sie nat&uuml;rlich auch einzeln behandeln:<\/p>\n<ul>\n<li class=\"aufz-hlung\">Keine Berechtigungen<\/li>\n<li class=\"aufz-hlung\">Lesen<\/li>\n<li class=\"aufz-hlung\">Schreiben<\/li>\n<li class=\"aufz-hlung\">L&ouml;schen<\/li>\n<\/ul>\n<p>Die erste Variante hat scheinbar einen Vorteil: Sie brauchen nur einen einzigen Wert zu speichern, welcher der jeweiligen Berechtigung entspricht (zum Beispiel die Zahlenwerte <b>1 <\/b>bis <b>4<\/b>). Im Datenmodell bedeutet dies, dass wir beispielsweise nur eine Eigenschaft f&uuml;r die entsprechende Benutzergruppe anlegen m&uuml;ssen. Bei der zweiten Variante m&uuml;ssten Sie schon mehrere Eigenschaften f&uuml;r das Festlegen der verschiedenen Berechtigungen speichern, denn eine Benutzergruppe kann ja beispielsweise nur lesende und l&ouml;schende Rechte besitzen.<\/p>\n<p>Aber auch dies l&auml;sst sich in einer einzigen Eigenschaft unterbringen: Dazu brauchen Sie die Berechtigungen lediglich mit Zweierpotenzen zu versehen (0, 1, 2, 4, 8, 16), die Sie durch Addieren als eine Zahl speichern k&ouml;nnen, aus der sich anschlie&szlig;end auch problemlos die Berechtigungen wiederherstellen lassen. Nat&uuml;rlich k&ouml;nnen Sie die Berechtigungen auch als Datens&auml;tze in einer Tabelle speichern und diese einer Benutzergruppe &uuml;ber eine m:n-Beziehung zuweisen, wie dies auch bei den Benutzern geschieht. Die Tabelle mit den Berechtigungen k&ouml;nnte dann etwa wie in Bild 20 aussehen.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic020_opt.jpeg\" alt=\"pic020.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 20: Tabelle mit verschiedenen Berechtigungen<\/span><\/b><\/p>\n<p>F&uuml;r das Zuweisen legen Sie noch eine Verkn&uuml;pfungstabelle an, die folgende drei Felder besitzt:<\/p>\n<ul>\n<li class=\"aufz-hlung\"><b>ID<\/b>: Prim&auml;rschl&uuml;sselfeld der Tabelle<\/li>\n<li class=\"aufz-hlung\"><b>BenutzergruppeID<\/b>: Fremdschl&uuml;sselfeld zum Feld <b>BenutzergruppeID <\/b>der Tabelle <b>tblBenutzergruppen<\/b><\/li>\n<li class=\"aufz-hlung\"><b>BerechtigungID<\/b>: Fremdschl&uuml;sselfeld zum Feld <b>BerechtigungID <\/b>der Tabelle <b>tblBerechtigungen<\/b><\/li>\n<\/ul>\n<p>F&uuml;r die beiden Fremdschl&uuml;sselfelder legen Sie wie schon in der Tabelle <b>tblBenutzerBenutzergruppen <\/b>einen zusammengesetzten, eindeutigen Schl&uuml;ssel fest. Au&szlig;erdem m&uuml;ssen Sie noch die entsprechenden Beziehungen definieren (siehe Bild 21).<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic021_opt.jpeg\" alt=\"pic021.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 21: m:n-Beziehung zwischen den Tabellen tblBenutzergruppen und tblBerechtigungen<\/span><\/b><\/p>\n<p><b>Formular zum Verwalten der Berechtigungen<\/b><\/p>\n<p>Das Formular zum Festlegen der Berechtigungen je Benutzergruppe k&ouml;nnten wir nun wieder genau so gestalten wie das zum Zuteilen von Benutzergruppen zu Benutzern, aber das w&auml;re ja langweilig. Wir gehen diesmal einen anderen Weg, dessen Ergebnis wie in Bild 22 aussieht.<\/p>\n<p><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2009_05\/Benutzerverwaltung-web-images\/pic023_opt.jpeg\" alt=\"pic023.png\" \/><\/p>\n<p><b><span style=\"color:darkgrey\">Bild 22: Alternative M&ouml;glichkeit zum Verwalten einer m:n-Beziehung<\/span><\/b><\/p>\n<p>Hier gibt es im Gegensatz zum Formular zum Zuweisen von Benutzergruppen nur ein Listenfeld. Dieses bietet allerdings die M&ouml;glichkeit einer Mehrfachauswahl an, wobei der Benutzer eine Berechtigung durch je einen einfachen Mausklick aus- und wieder abw&auml;hlen kann.<\/p>\n<p>Der Beitrag <b>Persistente Mehrfachauswahl in Listenfeldern <\/b>(s. Shortlink 479) schildert, wie die hier verwendeten Techniken funktionieren.<\/p>\n<p><b>Auswerten der Berechtigungen<\/b><\/p>\n<p>Schlie&szlig;lich wollen wir auch noch was von den m&uuml;hsam festgelegten Berechtigungen haben. Immerhin sollen diese daf&uuml;r sorgen, dass Benutzer bestimmte Funktionen, Formulare oder Men&uuml;eintr&auml;ge nicht nutzen k&ouml;nnen. Den gr&ouml;&szlig;ten Teil dieser Aufgabe m&uuml;ssen Sie selbst erledigen: Wir stellen nur eine einzige Funktion bereit, die Ihnen mitteilt, ob ein bestimmter Benutzer eine bestimmte Berechtigung besitzt.<\/p>\n<p>Diese Funktion hei&szlig;t <b>BerechtigungLesen<\/b> und erwartet zwei Parameter: die ID des Benutzers, f&uuml;r den die Berechtigung gepr&uuml;ft werden soll, und die Bezeichnung der Berechtigung. Sie k&ouml;nnen also hier beispielsweise folgenden Aufruf verwenden:<\/p>\n<pre>Debug.Print BerechtigungLesen(1, &quot;Schreiben&quot;)<\/pre>\n<p>Dies macht die Programmierung mitunter einfacher, weil man sich nicht die IDs der verschiedenen Berechtigungen merken und auch nicht immer in der Tabelle <b>tblBerechtigungen <\/b>nachsehen muss, wenn man einen Aufruf der Funktion zum Pr&uuml;fen der Berechtigungen programmieren m&ouml;chte.<\/p>\n<p>Die Funktion <b>BerechtigungLesen <\/b>liefert einen der beiden Werte <b>True <\/b>oder <b>False <\/b>zur&uuml;ck. Der Ablauf dieser Funktion (s. Listing 8) sieht so aus: Zun&auml;chst liest sie die ID der mit dem Parameter <b>strBerechtigung <\/b>&uuml;bergebenen Berechtigung aus der Tabelle <b>tblBerechtigungen <\/b>aus. Ist das Ergebnis dieser per <b>DLookup <\/b>durchgef&uuml;hrten Operation nicht <b>0<\/b>, ist die Berechtigung vorhanden und die Funktion kann weiterlaufen. Sie erstellt zun&auml;chst eine Datensatzgruppe, die alle Benutzergruppen des mit <b>BenutzerID <\/b>angegebenen Benutzers enth&auml;lt.<\/p>\n<p class=\"kastentabelleheader\">Listing 8: Diese Funktion ermittelt, ob ein bestimmter Benutzer &uuml;ber die angegebene Berechtigung verf&uuml;gt.<\/p>\n<pre>Public Function BerechtigungLesen(lngBenutzerID As Long, strBerechtigung As String) As Boolean\r\n    Dim db As DAO.Database\r\n    Dim rst As DAO.Recordset\r\n    Dim lngBerechtigungID As Long\r\n    Dim lngBenutzergruppeID As Long\r\n    Dim lngID As Long\r\n    Set db = CurrentDb\r\n    lngBerechtigungID = Nz(DLookup(&quot;BerechtigungID&quot;, &quot;tblBerechtigungen&quot;, _\r\n    &quot;Berechtigung = ''''&quot; &amp; strBerechtigung &amp; &quot;''''&quot;), 0)\r\n    If Not lngBerechtigungID = 0 Then\r\n        Set rst = db.OpenRecordset(&quot;SELECT BenutzergruppeID FROM tblBenutzerBenutzergruppen WHERE BenutzerID = &quot; _\r\n        &amp; lngBenutzerID, dbOpenDynaset)\r\n        Do While Not rst.EOF\r\n            lngBenutzergruppeID = rst!BenutzergruppeID\r\n            lngID = Nz(DLookup(&quot;ID&quot;, &quot;tblBenutzergruppenBerechtigungen&quot;, &quot;BenutzergruppeID = &quot; _\r\n            &amp; lngBenutzergruppeID &amp; &quot; AND BerechtigungID = &quot; &amp; lngBerechtigungID), 0)\r\n            If lngID &gt; 0 Then\r\n                BerechtigungLesen = True\r\n                Exit Function\r\n            End If\r\n            rst.MoveNext\r\n        Loop\r\n    End If\r\nEnd Function<\/pre>\n<p>Diese werden nacheinander durchlaufen, wobei eine weitere <b>DLookup<\/b>-Funktion nach einem Datensatz der Tabelle <b>tblBenutzergruppenBerechtigungen <\/b>sucht, der zu einer der Benutzergruppen des Benutzers und zur &uuml;bergebenen Berechtigung passt. Ist ein solcher Datensatz gefunden, stellt die Funktion den R&uuml;ckgabewert auf <b>True <\/b>ein und beendet sich selbst. Findet die Funktion keinen passenden Datensatz, gibt sie den Wert <b>False <\/b>an die aufrufende Prozedur zur&uuml;ck.<\/p>\n<p><b>Berechtigungssystem einsetzen<\/b><\/p>\n<p>Diese Funktion k&ouml;nnen Sie nun &uuml;berall einsetzen, wo in Abh&auml;ngigkeit vom angegebenen Benutzer Funktionen freigeschaltet oder nicht zur Verf&uuml;gung gestellt werden sollen. Zum Beispiel sollen in dieser Datenbank nur solche Benutzer, die der Gruppe <b>Administratoren <\/b>angeh&ouml;ren, die Berechtigung zum Verwalten der Benutzer besitzen. Dementsprechend sollen nur solche Benutzer das Formular <b>frmBenutzerBenutzergruppen <\/b>&ouml;ffnen k&ouml;nnen, die dazu berechtigt sind.<\/p>\n<p>Um dies zu realisieren, legen Sie f&uuml;r das <b>Beim &Ouml;ffnen<\/b>-Ereignis die folgende Ereignisprozedur fest:<\/p>\n<pre>Private Sub Form_Open(Cancel As Integer)\r\n    Dim lngAktuellerBenutzerID As Long\r\n    lngAktuellerBenutzerID = _\r\n    CLng(OptionLesen(&quot;CurrentUserID&quot;))\r\n    If Not BerechtigungLesen( _\r\n    lngAktuellerBenutzerID, &quot;Verwalten&quot;) Then\r\n    Cancel = True\r\n    MsgBox &quot;Sie haben keine Berechtigung, &quot; _\r\n    &amp; &quot;dieses Formular zu &ouml;ffnen.&quot;\r\nEnd If\r\nEnd Sub<\/pre>\n<p>Die Prozedur pr&uuml;ft mit der Funktion <b>BerechtigungLesen<\/b>, ob der angemeldete Benutzer (also der, den die Anwendung beim Start in der Tabelle <b>tblOptionen <\/b>gespeichert hat) die Berechtigung mit der Bezeichnung <b>Verwalten <\/b>besitzt.<\/p>\n<p><b>Zusammenfassung und Ausblick<\/b><\/p>\n<p>Zusammen mit einigen Beispielen f&uuml;r das Erstellen von Formularen zur Verwaltung von m:n-Beziehungen und sonstigen Techniken haben Sie erfahren, wie Sie Benutzer und Benutzergruppen einander zuordnen und wie Sie f&uuml;r die verschiedenen Benutzergruppen Berechtigungen festlegen. Ein einfaches Beispiel hat gezeigt, wie Sie die Berechtigungsdaten nach der Anmeldung eines Benutzers einsetzen k&ouml;nnen, um den Zugriff auf ein Formular einzuschr&auml;nken.<\/p>\n<p>Nat&uuml;rlich k&ouml;nnen Sie die L&ouml;sung nach Belieben aufbohren, um differenzierte Berechtigungen etwa f&uuml;r verschiedene Objekte der Datenbankanwendung zu vergeben &#8211; oder Sie entscheiden sich, dass Sie nicht nur f&uuml;r Benutzergruppen, sondern auch f&uuml;r einzelne Benutzer Berechtigungen festlegen m&ouml;chten.<\/p>\n<p>Au&szlig;erdem k&ouml;nnte man die Kennw&ouml;rter noch verschl&uuml;sselt speichern. Wie dies funktioniert, erl&auml;utert der Beitrag <b>Datenverschl&uuml;sselung<\/b> (Shortlink 438).<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>Benutzerverwaltung.mdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/{538ECF27-AC16-43E5-83C4-63ED3501E1B7}\/aiu_688.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Bis Access 2003 unterst&uuml;tzte Access den Entwickler durch eine Benutzerverwaltung inklusive Sicherheitssystem. Neuere Access-Versionen bieten dies nicht mehr. Kein gro&szlig;es Problem: Das Sicherheitssystem war ohnehin nicht besonders sicher, und die Benutzerverwaltung m&ouml;chten Sie vielleicht ohnehin selbst gestalten. In diesem Beitrag zeigen wir, wie Sie eine solche Benutzerverwaltung gestalten und einsetzen.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"om_disable_all_campaigns":false,"_monsterinsights_skip_tracking":false,"_monsterinsights_sitenote_active":false,"_monsterinsights_sitenote_note":"","_monsterinsights_sitenote_category":0,"_uf_show_specific_survey":0,"_uf_disable_surveys":false,"footnotes":""},"categories":[662009,66052009,44000028,44000023],"tags":[],"class_list":["post-55000688","post","type-post","status-publish","format-standard","hentry","category-662009","category-66052009","category-Ergonomie_und_Benutzeroberflaeche","category-Mit_Formularen_arbeiten"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.3) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Benutzerverwaltung - Access im Unternehmen<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Benutzerverwaltung\" \/>\n<meta property=\"og:description\" content=\"Bis Access 2003 unterst&uuml;tzte Access den Entwickler durch eine Benutzerverwaltung inklusive Sicherheitssystem. Neuere Access-Versionen bieten dies nicht mehr. Kein gro&szlig;es Problem: Das Sicherheitssystem war ohnehin nicht besonders sicher, und die Benutzerverwaltung m&ouml;chten Sie vielleicht ohnehin selbst gestalten. In diesem Beitrag zeigen wir, wie Sie eine solche Benutzerverwaltung gestalten und einsetzen.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-22T22:18:09+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a\" \/>\n<meta name=\"author\" content=\"Andr\u00e9 Minhorst\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Verfasst von\" \/>\n\t<meta name=\"twitter:data1\" content=\"Andr\u00e9 Minhorst\" \/>\n\t<meta name=\"twitter:label2\" content=\"Gesch\u00e4tzte Lesezeit\" \/>\n\t<meta name=\"twitter:data2\" content=\"44\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Benutzerverwaltung\",\"datePublished\":\"2020-05-22T22:18:09+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/\"},\"wordCount\":7819,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/6d53f6a2454d4ae484424272ab871b2a\",\"articleSection\":[\"2009\",\"5\\\/2009\",\"Ergonomie und Benutzeroberfl\u00e4che\",\"Mit Formularen arbeiten\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/\",\"name\":\"Benutzerverwaltung - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/6d53f6a2454d4ae484424272ab871b2a\",\"datePublished\":\"2020-05-22T22:18:09+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/6d53f6a2454d4ae484424272ab871b2a\",\"contentUrl\":\"http:\\\/\\\/vg09.met.vgwort.de\\\/na\\\/6d53f6a2454d4ae484424272ab871b2a\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzerverwaltung\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Benutzerverwaltung\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"name\":\"Access im Unternehmen\",\"description\":\"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access\",\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/access-im-unternehmen.de\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"de\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\",\"name\":\"Andr\u00e9 Minhorst Verlag\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"contentUrl\":\"https:\\\/\\\/access-im-unternehmen.de\\\/wp-content\\\/uploads\\\/2019\\\/09\\\/aiu_wp.png\",\"width\":370,\"height\":111,\"caption\":\"Andr\u00e9 Minhorst Verlag\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\",\"name\":\"Andr\u00e9 Minhorst\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g\",\"caption\":\"Andr\u00e9 Minhorst\"}}]}<\/script>\n<!-- \/ Yoast SEO Premium plugin. -->","yoast_head_json":{"title":"Benutzerverwaltung - Access im Unternehmen","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/","og_locale":"de_DE","og_type":"article","og_title":"Benutzerverwaltung","og_description":"Bis Access 2003 unterst&uuml;tzte Access den Entwickler durch eine Benutzerverwaltung inklusive Sicherheitssystem. Neuere Access-Versionen bieten dies nicht mehr. Kein gro&szlig;es Problem: Das Sicherheitssystem war ohnehin nicht besonders sicher, und die Benutzerverwaltung m&ouml;chten Sie vielleicht ohnehin selbst gestalten. In diesem Beitrag zeigen wir, wie Sie eine solche Benutzerverwaltung gestalten und einsetzen.","og_url":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-22T22:18:09+00:00","og_image":[{"url":"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"44\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Benutzerverwaltung","datePublished":"2020-05-22T22:18:09+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/"},"wordCount":7819,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a","articleSection":["2009","5\/2009","Ergonomie und Benutzeroberfl\u00e4che","Mit Formularen arbeiten"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/","url":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/","name":"Benutzerverwaltung - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#primaryimage"},"thumbnailUrl":"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a","datePublished":"2020-05-22T22:18:09+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#primaryimage","url":"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a","contentUrl":"http:\/\/vg09.met.vgwort.de\/na\/6d53f6a2454d4ae484424272ab871b2a"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Benutzerverwaltung\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Benutzerverwaltung"}]},{"@type":"WebSite","@id":"https:\/\/access-im-unternehmen.de\/#website","url":"https:\/\/access-im-unternehmen.de\/","name":"Access im Unternehmen","description":"Das Magazin f\u00fcr Datenbankentwickler auf Basis von Microsoft Access","publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/access-im-unternehmen.de\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"de"},{"@type":"Organization","@id":"https:\/\/access-im-unternehmen.de\/#organization","name":"Andr\u00e9 Minhorst Verlag","url":"https:\/\/access-im-unternehmen.de\/","logo":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/","url":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","contentUrl":"https:\/\/access-im-unternehmen.de\/wp-content\/uploads\/2019\/09\/aiu_wp.png","width":370,"height":111,"caption":"Andr\u00e9 Minhorst Verlag"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f","name":"Andr\u00e9 Minhorst","image":{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/1b9d010cf1716692cb9c34f21554e07d17d461acaea5b61b8cb21cbec678d48a?s=96&d=mm&r=g","caption":"Andr\u00e9 Minhorst"}}]}},"_links":{"self":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000688","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/comments?post=55000688"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55000688\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55000688"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55000688"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55000688"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}