{"id":55001192,"date":"2019-06-01T00:00:00","date_gmt":"2020-05-13T20:55:00","guid":{"rendered":"http:\/\/access-im-unternehmen.aix-dev.de\/aiu\/?p=1192"},"modified":"-0001-11-30T00:00:00","modified_gmt":"-0001-11-30T00:00:00","slug":"Benutzer_und_Berechtigungen_ermitteln","status":"publish","type":"post","link":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/","title":{"rendered":"Benutzer und Berechtigungen ermitteln"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5\" width=\"1\" height=\"1\" alt=\"\"><\/p>\n<p><b>In den Beitr&auml;gen &#8222;Benutzerverwaltung mit verschl&uuml;sselten Kennw&ouml;rtern&#8220; und &#8222;Berechtigungen per HTML verwalten&#8220; haben wir die Voraussetzungen f&uuml;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&szlig;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.<\/b><\/p>\n<p>In den Beitr&auml;gen <b>Benutzerverwaltung mit verschl&uuml;sselten Kennw&ouml;rtern <\/b>(<b>www.access-im-unternehmen.de\/1190<\/b>) und <b>Berechtigungen per HTML verwalten <\/b>(<b>www.access-im-unternehmen.de\/1191<\/b>) haben wir das Datenmodell und die Formulare zur Verwaltung unseres Berechtigungssystems vorbereitet.<\/p>\n<p>Daraus ist das Datenmodell aus Bild 1 entstanden, auf dem dieser Beitrag aufbaut. F&uuml;r die Anmeldung an der Anwendung ben&ouml;tigen wir lediglich die Tabelle <b>tblBenutzer<\/b>. Wir erstellen dazu ein Formular, mit dem der Benutzer seinen Benutzernamen sowie das Kennwort eingeben kann und das dann pr&uuml;ft, ob die Daten mit den gespeicherten Daten &uuml;bereinstimmen. Falls nicht, kann der Benutzer sich bei Bedarf ein neues Kennwort zusenden lassen beziehungsweise dieses &auml;ndern. Im zweiten Teil verwenden Sie die Daten der aktuellen Anmeldung dann dazu, um die Berechtigung f&uuml;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.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_001.png\" alt=\"Datenmodell der Berechtigungsverwaltung\" width=\"700\" height=\"285,068\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 1: Datenmodell der Berechtigungsverwaltung<\/span><\/b><\/p>\n<h2>Anmeldeformular programmieren<\/h2>\n<p>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&auml;che zum Best&auml;tigen der Eingabe und eine zum Beenden der Anmeldung, die dann auch die Anwendung schlie&szlig;t. Der Entwurf sieht also im ersten Anlauf etwa wie in Bild 2 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_002.png\" alt=\"Entwurf des Anmeldeformulars\" width=\"349,7625\" height=\"264,3091\"\/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 2: Entwurf des Anmeldeformulars<\/span><\/b><\/p>\n<p>Das Formular enth&auml;lt nun neben dem Bezeichnungsfeld mit dem Text <b>Anmeldung <\/b>die folgenden Steuer-elemente:<\/p>\n<ul>\n<li><b>txtBenutzername<\/b>: Textfeld zur Eingabe des Benutzernamens<\/li>\n<li><b>txtKennwort<\/b>: Textfeld zur Eingabe des Kennworts mit einem Eingabeformat zum Maskieren der Eingabe <\/li>\n<li><b>cmdAnmelden<\/b>: Schaltfl&auml;che, die eine Prozedur zum Pr&uuml;fen der Kombination aus Benutzername und Kennwort aufruft<\/li>\n<li><b>cmdAbbrechen<\/b>: Schaltfl&auml;che, die das Formular und die Anwendung schlie&szlig;t<\/li>\n<\/ul>\n<p>F&uuml;r das Textfeld <b>txtKennwort<\/b> legen wir das Eingabeformat <b>Kennwort <\/b>fest. Dazu klicken Sie rechts in der Eigenschaft <b>Eingabeformat <\/b>f&uuml;r dieses Textfeld auf die Schaltfl&auml;che mit den drei Punkten (<b>&#8230;<\/b>). Es erscheint der Dialog <b>Eingabeformat-Assistent<\/b>, wo Sie das Eingabeformat Kennwort ausw&auml;hlen (siehe Bild 3).<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_003.png\" alt=\"Einstellen des Eingabeformats\" width=\"599,593\" height=\"528,629\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 3: Einstellen des Eingabeformats<\/span><\/b><\/p>\n<p>Anschlie&szlig;end wird die Eingabe des Textes im Textfeld <b>txtKennwort <\/b>durch Sternchen maskiert (siehe Bild 4). An dieser Stelle legen wir f&uuml;r die Eigenschaften <b>Datensatzmarkierer<\/b>, <b>Navigationsschaltfl&auml;chen<\/b>, <b>Bildlaufleisten <\/b>und <b>Trennlinien <\/b>den Wert <b>Nein <\/b>und f&uuml;r <b>Automatisch zentrieren <\/b>den Wert <b>Ja <\/b>fest, damit die entsprechenden Elemente nicht mehr erscheinen beziehungsweise das Anmeldeformular in der Mitte des Access-Fensters angezeigt wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_004.png\" alt=\"Verbergen der Kennworteingabe\" width=\"349,7625\" height=\"264,3091\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 4: Verbergen der Kennworteingabe<\/span><\/b><\/p>\n<h2>Pr&uuml;fen von Benutzername und Kennwort<\/h2>\n<p>Wenn der Benutzer auf die Schaltfl&auml;che <b>cmdAnmelden <\/b>klickt, soll eine Prozedur pr&uuml;fen, ob Benutzername und Kennwort zusammengeh&ouml;ren. Diese gestalten wir erst einmal so einfach wie m&ouml;glich. Die Ereignisprozedur soll erst einmal pr&uuml;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 <b>tblBenutzer <\/b>gespeichert ist:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>cmdAnmelden_Click()\r\n     If AnmeldungPruefen(Me!txtBenutzername, _\r\n             Me!txtKennwort) = <span style=\"color:blue;\">True<\/span> Then\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Anmeldung erfolgreich.\"\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         <span style=\"color:blue;\">MsgBox<\/span> \"Anmeldung nicht erfolgreich.\"\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Die Funktion <b>AnmeldungPruefen <\/b>finden Sie in Listing 1. Die Funktion ber&uuml;cksichtigt, dass wir die Kennw&ouml;rter nicht im Klartext im Feld <b>Kennwort <\/b>der Tabelle <b>tblBenutzer <\/b>speichern, sondern in verschl&uuml;sselter Form. Sie nimmt die zu untersuchende Kombination von Benutzername und Kennwort in Form der beiden Parameter <b>strBenutzername <\/b>und <b>strKennwort <\/b>entgegen. Dann erstellt sie eine neue Instanz der Klasse <b>clsCrypt<\/b>, die unter anderem eine Methode zum Verschl&uuml;sseln mit dem <b>SHA1<\/b>-Algorithmus bereitstellt. Diese Methode verschl&uuml;sselt dann das Kennwort aus <b>strKennwort<\/b>. Das Ergebnis landet in der Variablen <b>strVerschluesselt<\/b>.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AnmeldungPruefen(strBenutzername<span style=\"color:blue;\"> As String<\/span>, strKennwort<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>objCrypt<span style=\"color:blue;\"> As <\/span>clsCrypt\r\n     <span style=\"color:blue;\">Dim <\/span>strVerschluesselt<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> objCrypt = <span style=\"color:blue;\">New<\/span> clsCrypt\r\n     strVerschluesselt = objCrypt.GetSHA1(strKennwort)\r\n     If <span style=\"color:blue;\">Not<\/span> IsNull(DLookup(\"BenutzerID\", \"tblBenutzer\", \"Benutzername = ''\" & strBenutzername & \"'' AND Kennwort = ''\" _\r\n             & strVerschluesselt & \"''\")) Then\r\n         AnmeldungPruefen = <span style=\"color:blue;\">True<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 1: Funktion zum Pr&uuml;fen einer Anmeldung<\/span><\/b><\/p>\n<p>Damit k&ouml;nnen wir dann &uuml;ber den Aufruf einer <b>DLookup<\/b>-Funktion pr&uuml;fen, ob die Kombination aus Benutzername und <b>SHA1<\/b>-verschl&uuml;sseltem Kennwort in der Tabelle <b>tblBenutzer <\/b>vorkommt. Ist dies der Fall, liefert die Funktion <b>AnmeldungPruefen <\/b>den Wert <b>True <\/b>zur&uuml;ck, anderenfalls den Wert <b>False<\/b>.<\/p>\n<h2>Nach der Anmeldung<\/h2>\n<p>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 &#8211; eine &ouml;ffentliche Variable Nein, denn wir wollen sp&auml;ter im Beitrag <b>Zugriffsrechte mit Datenmakros<\/b> (<b>www.access-im-unternehmen.de\/1193<\/b>) auch auf diese Information zugreifen.<\/p>\n<p>Das ist dort am einfachsten m&ouml;glich &uuml;ber eine in der <b>TempVars<\/b>-Auflistung gespeicherte Variable.<\/p>\n<p>Also ersetzen wir die <b>MsgBox<\/b>-Anweisung in der Prozedur <b>cmdAnmelden_Click <\/b>durch die folgenden beiden Zeilen:<\/p>\n<pre><span style=\"color:blue;\">If <\/span>AnmeldungPruefen(Me!txtBenutzername, Me!txtKennwort) = <span style=\"color:blue;\">True<\/span><span style=\"color:blue;\"> Then<\/span>\r\n     TempVars.Add \"Benutzername\", Me!txtBenutzername.Value\r\n     DoCmd.Close acForm, Me.Name\r\n<span style=\"color:blue;\">Else<\/span><\/pre>\n<p>Danach k&ouml;nnen wir wie folgt auf den Wert der tempor&auml;ren Variablen zugreifen:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> TempVars!Benutzername\r\nPeter Gross<\/pre>\n<p>Wenn die Anmeldung fehlschl&auml;gt, soll die tempor&auml;re Variable &uuml;brigens wieder geleert werden:<\/p>\n<pre>TempVars.Remove \"Benutzername\"<\/pre>\n<h2>Bei nicht erfolgreicher Anmeldung<\/h2>\n<p>Wenn der Benutzer nicht die richtigen Daten eingibt, erscheint aktuell jeweils die Meldung mit dem Text <b>Anmeldung nicht erfolgreich<\/b>. Hier k&ouml;nnten wir nun beispielsweise pr&uuml;fen, ob ein Benutzer mehrfach versucht, sich mit dem gleichen Benutzernamen anzumelden und dabei immer wieder das falsche Kennwort eingibt.<\/p>\n<p>Ist das der Fall, k&ouml;nnte man verschiedene Aktionen durchf&uuml;hren &#8211; beispielsweise die Zeit zwischen den m&ouml;glichen Anmeldeversuchen schrittweise vergr&ouml;&szlig;ern, um zu verhindern, dass jemand automatisiert versucht, das Kennwort f&uuml;r den Benutzernamen zu ermitteln.<\/p>\n<p>Hier wird es schon interessant, denn diese Informationen m&uuml;ssen wir ebenfalls speichern, um beim n&auml;chsten Anmeldeversuch wieder darauf zugreifen zu k&ouml;nnen. Zun&auml;chst legen wir fest, wieviel Zeit zwischen zwei Anmeldeversuchen verstreichen soll.<\/p>\n<p>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.<\/p>\n<p>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&auml;chst die Wartezeit zwischen zwei Anmeldeversuchen schnell an.<\/p>\n<p>Welche Informationen m&uuml;ssen wir dazu speichern Wir ben&ouml;tigen den Benutzernamen, denn die Anmeldungen sollen nur f&uuml;r Versuche mit dem gleichen Benutzernamen gez&auml;hlt werden. Dann ben&ouml;tigen wir die Anzahl der Versuche seit der letzten erfolgreichen Anmeldung und den Zeitpunkt des letzten erfolglosen Versuchs.<\/p>\n<p>Diese Informationen k&ouml;nnen wir am besten direkt in der Benutzertabelle speichern, da diese ja ohnehin bereits f&uuml;r jeden Benutzer einen Datensatz enth&auml;lt. Also f&uuml;gen wir die folgenden Felder wie in Bild 5 hinzu:<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_005.png\" alt=\"Neue Felder in der Tabelle tblBenutzer\" width=\"700\" height=\"145,8046\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 5: Neue Felder in der Tabelle tblBenutzer<\/span><\/b><\/p>\n<ul>\n<li><b>LetzteErfolgreicheAnmeldung<\/b>: Datum und Uhrzeit des letzten erfolgreichen Anmeldeversuchs<\/li>\n<li><b>LetzteFehlgeschlageneAnmeldung<\/b>: Datum und Uhrzeit des letzten fehlgeschlagenen Anmeldeversuchs<\/li>\n<li><b>AnzahlFehlgeschlageneAnmeldungen<\/b>: Anzahl der fehlgeschlagenen Anmeldungen seit der letzten erfolgreichen Anmeldung<\/li>\n<\/ul>\n<h2>Integration der Wartezeit in den Anmeldedialog<\/h2>\n<p>Die Daten dieser drei Felder &auml;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 <b>LetzteErfolgreicheAnmeldung <\/b>ein und stellen den Wert des Feldes <b>AnzahlFehlgeschlageneAnmeldungen <\/b>auf <b>0 <\/b>ein.<\/p>\n<p>Bei einem gescheiterten Anmeldeversuch stellen wir das Feld <b>LetzteFehlgeschlageneAnmeldung <\/b>auf das aktuelle Datum plus Uhrzeit ein und erh&ouml;hen den Wert des Feldes <b>AnzahlFehlgeschlageneAnmeldungen <\/b>um <b>1<\/b>.<\/p>\n<p>Auf diese Weise k&ouml;nnen wir allerdings nur Anmeldeversuche behandeln, f&uuml;r die ein g&uuml;ltiger Benutzername angegeben wurde. Wenn kein Benutzername angegeben wurde, k&ouml;nnen wir auch keine Informationen &uuml;ber die letzte Anmeldung des Benutzers in der Tabelle <b>tblBenutzer <\/b>speichern. Wie gehen wir dann vor Ignorieren wir Anmeldeversuche ohne g&uuml;ltigen Benutzernamen, weil der Benutzer &#8211; auch wenn er b&ouml;se Absichten hat &#8211; ohne Kenntnis eines g&uuml;ltigen Benutzernamens noch weiter von einer erfolgreichen Anmeldung entfernt ist als mit Benutzername Oder sollten wir auch hier eine zeitliche Barriere einf&uuml;hren Wir wollen es einfach halten und ignorieren Anmeldungen ohne g&uuml;ltigen Benutzernamen einfach.<\/p>\n<p>Die Funktion <b>AnmeldungPruefen <\/b>&auml;ndern wir wie in Listing 2. Wir haben statt der <b>DLookup<\/b>-Funktion direkt den Zugriff auf den Datensatz der Tabelle <b>tblBenutzer <\/b>mit dem passenden Benutzernamen als Recordset implementiert. Das hei&szlig;t, dass wir nach dem Ermitteln des verschl&uuml;sselten Kennworts ein Recordset &ouml;ffnen, das den Datensatz der Tabelle <b>tblBenutzer <\/b>mit dem Benutzernamen aus dem Parameter <b>strBenutzername <\/b>enth&auml;lt. Ist dieses Recordset leer, hat der Benutzer einen ung&uuml;ltigen Benutzernamen eingegeben und die Funktion soll den Wert <b>False <\/b>zur&uuml;ckliefern. Ist das Recordset nicht leer, hat der Benutzer zumindest einen g&uuml;ltigen Benutzernamen angegeben.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>AnmeldungPruefen(strBenutzername<span style=\"color:blue;\"> As String<\/span>, strKennwort<span style=\"color:blue;\"> As String<\/span>)\r\n     <span style=\"color:blue;\">Dim <\/span>objCrypt<span style=\"color:blue;\"> As <\/span>clsCrypt\r\n     <span style=\"color:blue;\">Dim <\/span>strVerschluesselt<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> objCrypt = <span style=\"color:blue;\">New<\/span> clsCrypt\r\n     strVerschluesselt = objCrypt.GetSHA1(strKennwort)\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM tblBenutzer WHERE Benutzername = ''\" & strBenutzername & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rst.EOF<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span>strVerschluesselt = rst!Kennwort<span style=\"color:blue;\"> Then<\/span>\r\n             rst.Edit\r\n             rst!LetzteErfolgreicheAnmeldung = Now\r\n             rst!AnzahlFehlgeschlageneAnmeldungen = 0\r\n             rst.Update\r\n             AnmeldungPruefen = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             rst.Edit\r\n             rst!LetzteFehlgeschlageneAnmeldung = Now\r\n             rst!AnzahlFehlgeschlageneAnmeldungen = Nz(rst!AnzahlFehlgeschlageneAnmeldungen, 0) + 1\r\n             rst.Update\r\n             AnmeldungPruefen = <span style=\"color:blue;\">False<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">Else<\/span>\r\n         AnmeldungPruefen = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><!--30percent--><\/p>\n<p><b><span style=\"color:darkgrey;\">Listing 2: Funktion zum Pr&uuml;fen einer Anmeldung, erweiterte Fassung<\/span><\/b><\/p>\n<p>Dann pr&uuml;fen wir in einer <b>If&#8230;Then<\/b>-Bedingung, ob das verschl&uuml;sselte Kennwort aus <b>strVerschluesselt <\/b>mit der im Feld <b>Kennwort <\/b>gespeicherten, verschl&uuml;sselten Version des Kennworts f&uuml;r diesen Benutzer &uuml;bereinstimmt. In diesem Fall versetzen wir das Recordset mit der <b>Edit<\/b>-Methode in den Verarbeitungsmodus und stellen zwei Felder auf neue Werte ein. Das Feld <b>LetzteErfolgreicheAnmeldung <\/b>erh&auml;lt mit der Funktion <b>Now <\/b>das aktuelle Datum plus Uhrzeit, das Feld <b>AnzahlFehlgeschlageneAnmeldungen <\/b>stellen wir auf den Wert <b>0 <\/b>ein. Danach speichern wir den aktualisierten Datensatz mit der <b>Update<\/b>-Methode und geben den Wert <b>True <\/b>als Funktionswert zur&uuml;ck.<\/p>\n<p>Stimmt das verschl&uuml;sselte Kennwort nicht mit dem Wert aus dem Feld <b>Kennwort <\/b>&uuml;berein, bearbeiten wir den aktuellen Datensatz ebenfalls. Hier legen wir den Wert des Feldes <b>LetzteFehlgeschlageneAnmeldung <\/b>auf das Ergebnis der Funktion <b>Now <\/b>fest und erh&ouml;hen den Wert des Feldes <b>AnzahlFehlgeschlageneAnmeldungen <\/b>auf den vorherigen Wert plus <b>1<\/b>. Falls das Feld vorher noch leer war, erh&auml;lt das Feld den Wert <b>1<\/b>. In diesem Fall geben wir den Wert <b>False <\/b>als Funktionsergebnis zur&uuml;ck.<\/p>\n<p>Der entsprechende Datensatz sieht nach drei fehlgeschlagenen Anmeldungen und ohne erfolgreiche Anmeldung beispielsweise wie in Bild 6 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_006.png\" alt=\"Speichern fehlgeschlagener Anmeldungen\" width=\"700\" height=\"138,6792\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 6: Speichern fehlgeschlagener Anmeldungen<\/span><\/b><\/p>\n<h2>Zeitverz&ouml;gerung beim Anmelden<\/h2>\n<p>Nun m&uuml;ssen wir noch daf&uuml;r sorgen, dass das Formular <b>frmAnmeldung <\/b>beim Versuch, sich unter einem Benutzernamen anzumelden, f&uuml;r den es seit der letzten erfolgreichen Anmeldung einen oder mehrere fehlgeschlagene Anmeldungen gab, eine zeitliche Sperre einrichtet und den Benutzer auch dar&uuml;ber informiert.<\/p>\n<p>Was wir daf&uuml;r zweifelsohne ben&ouml;tigen, ist die Ereignisprozedur <b>Bei Zeitgeber <\/b>sowie ein entsprechendes Intervall f&uuml;r die Eigenschaft <b>Zeitgeberintervall<\/b>, das angibt, nach welchem Zeitraum das Ereignis <b>Bei Zeitgeber <\/b>das n&auml;chste Mal ausgel&ouml;st werden soll. Die Eigenschaft <b>Zeitgeberintervall <\/b>statten wir mit dem Zeitraum &uuml;ber eine Sekunde aus, was dem Wert <b>1.000 <\/b>(in Millisekunden) entspricht.<\/p>\n<p>Wie genau soll die Anzeige der Zeitverz&ouml;gerung nach mehreren fehlgeschlagenen Anmeldeversuchen mit g&uuml;ltigem Benutzernamen, aber mit falschem Kennwort erfolgen Wir m&uuml;ssen als Erstes pr&uuml;fen, ob das Textfeld <b>txtBenutzername <\/b>&uuml;berhaupt einen g&uuml;ltigen Benutzernamen anzeigt.<\/p>\n<p>Nur dann k&ouml;nnen wir aus der Tabelle <b>tblBenutzer <\/b>die Werte der Felder <b>LetzteFehlgeschlageneAnmeldung<\/b> und <b>AnzahlFehlgeschlageneAnmeldungen<\/b> f&uuml;r diesen Benutzer ermitteln. Danach k&ouml;nnen wir pr&uuml;fen, wie lange nach dem letzten Anmeldeversuch ein erneuter Versuch noch unterbunden werden soll.<\/p>\n<p>Dann ermitteln wir, bis zu welchem Zeitpunkt ausgehend von der letzten fehlgeschlagenen Anmeldung und der Anzahl der fehlgeschlagenen Anmeldungen eine weitere Anmeldung unter diesem Benutzernamen unterbunden werden soll.<\/p>\n<p>Theoretisch m&uuml;ssten wir also immer wieder auf die Daten der Tabelle <b>tblBenutzer <\/b>zugreifen &#8211; wenn wir das in der Ereignisprozedur <b>Form_Timer <\/b>erledigen, sogar jede Sekunde. Das ist sicher ein wenig &uuml;bertrieben.<\/p>\n<p>Wie aber k&ouml;nnen wir die Anzahl der Zugriffe verringern &#8211; vor allem, weil wir ja die Daten zum Zeitpunkt der letzten gescheiterten Anmeldung und die Anzahl der gescheiterten Anmeldungen seit der letzten erfolgreichen Anmeldung bei jedem Aufruf von <b>Form_Timer <\/b>ben&ouml;tigen<\/p>\n<p>Ein Ansatz ist, das Recordset immer dann neu zu laden, wenn der Benutzer einen neuen Benutzernamen in das Formular <b>frmAnmeldung <\/b>eingegeben hat. Das k&ouml;nnten wir so erledigen, dass wir einmalig beim &Ouml;ffnen des Formulars alle Benutzernamen in eine Collection oder ein &auml;hnliches Objekt einlesen und dann bei der Eingabe eines Benutzernamens in das Textfeld <b>txtBenutzername <\/b>pr&uuml;fen, ob der Benutzername in der Tabelle <b>tblBenutzer <\/b>enthalten ist.<\/p>\n<p>Eine m&ouml;gliche Collection-Art f&uuml;r diesen Zweck ist das <b>Dictionary<\/b>-Objekt. In diesem k&ouml;nnen wir den Namen des Benutzers als Schl&uuml;ssel speichern und auch schnell pr&uuml;fen, ob es einen Eintrag mit dem gesuchten Benutzernamen gibt. Um das <b>Dictionary<\/b>-Objekt mit Early Binding nutzen und damit auf IntelliSense zugreifen zu k&ouml;nnen, f&uuml;gen Sie einen Verweis auf die Bibliothek <b>Microsoft Scripting Runtime <\/b>wie in Bild 7 zum VBA-Projekt der Anwendung hinzu.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_007.png\" alt=\"Verweis auf die Bibliothek Microsoft Scripting Runtime\" width=\"424,7115\" height=\"334,8159\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 7: Verweis auf die Bibliothek Microsoft Scripting Runtime<\/span><\/b><\/p>\n<p>F&uuml;r unseren Einsatzzweck ben&ouml;tigen wir drei Variablen, die wir im Kopf des Klassenmoduls des Formulars <b>frmAnmeldung <\/b>anlegen:<\/p>\n<pre><span style=\"color:blue;\">Dim <\/span>rstBenutzer<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n<span style=\"color:blue;\">Dim <\/span>strBenutzername<span style=\"color:blue;\"> As String<\/span>\r\n<span style=\"color:blue;\">Dim <\/span>dicBenutzer<span style=\"color:blue;\"> As <\/span>Dictionary<\/pre>\n<p>Die erste soll das Recordset mit dem Datensatz der Tabelle <b>tblBenutzer <\/b>aufnehmen, wenn der Benutzer einen g&uuml;ltigen Benutzernamen in das Textfeld <b>txtBenutzername <\/b>eingegeben hat. Den Benutzernamen speichern wir nach der Eingabe in der Variablen <b>strBenutzername<\/b>. Und das <b>Dictionary<\/b>-Objekt, das alle Benutzernamen der Tabelle <b>tblBenutzer <\/b>aufnehmen soll, nennen wir <b>dicBenutzer<\/b>.<\/p>\n<h2>Dictionary beim Laden mit Benutzernamen f&uuml;llen<\/h2>\n<p>Wenn das Formular <b>frmAnmeldung <\/b>ge&ouml;ffnet wird, wollen wir alle Benutzernamen aus der Tabelle <b>tblBenutzer <\/b>in das Dictionary <b>dicBenutzer <\/b>schreiben. Das erledigen wir in der Ereignisprozedur, die durch das Ereignis <b>Beim Laden <\/b>ausgel&ouml;st wird. Dazu instanzieren wir zun&auml;chst das Objekt <b>dicBenutzer <\/b>als neues <b>Dictionary<\/b>-Objekt. Der <b>Database<\/b>-Variablen <b>db <\/b>weisen wir die aktuelle Datenbank zu, dem <b>Recordset<\/b>-Objekt <b>rst <\/b>alle Datens&auml;tze der Tabelle <b>tblBenutzer <\/b>&#8211; allerdings ben&ouml;tigen wir davon nur den Inhalt des Feldes <b>Benutzername<\/b>. In einer <b>Do While<\/b>-Schleife &uuml;ber alle Datens&auml;tze durchlaufen wir dann das Recordset <b>rst <\/b>und weisen den Inhalt des Feldes <b>Benutzername <\/b>f&uuml;r alle Datens&auml;tze mit der <b>Add<\/b>-Methode als neuen Eintrag zum <b>Dictionary<\/b>-Objekt hinzu.<\/p>\n<p>Dabei geben wir den Benutzernamen sowohl als Schl&uuml;ssel als auch als Wert des neuen Eintrags an. Wichtig ist hier, dass wir nicht nur <b>rst!Benutzername <\/b>angeben, sondern <b>rst!Benutzername.Value <\/b>&#8211; sonst f&uuml;gt die Prozedur nicht den Wert, sondern den Verweis auf das Feld des Recordsets zum <b>Dictionary<\/b>-Objekt hinzu. Und das w&uuml;rde dann direkt beim zweiten Durchlauf der <b>Do While<\/b>-Schleife zum Fehler f&uuml;hren, weil der Verweis ja schon im ersten Durchlauf hinzugef&uuml;gt wurde und der Schl&uuml;ssel eindeutig sein muss:<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Load()\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Set<\/span> dicBenutzer = <span style=\"color:blue;\">New<\/span> Dictionary\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT Benutzername  FROM tblBenutzer\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         dicBenutzer.Add rst!Benutzername.Value,  rst!Benutzername.Value\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p>Nun wollen wir immer dann, wenn der Benutzername sich &auml;ndert, pr&uuml;fen, ob der Benutzer gerade einen g&uuml;ltigen Benutzernamen eingegeben hat. Das erledigen wir in der Ereignisprozedur, die durch das Ereignis <b>Beim &Auml;ndern <\/b>des Textfeldes <b>txtBenutzername <\/b>ausgel&ouml;st wird. Diese sieht wie in Listing 3 aus und &uuml;bertr&auml;gt zun&auml;chst den aktuell eingegebenen Wert im Textfeld <b>txtBenutzer <\/b>in die Variable <b>strBenutzer<\/b>. Dann pr&uuml;ft sie, ob das <b>Dictionary<\/b>-Objekt <b>dicBenutzer <\/b>einen Eintrag enth&auml;lt, dessen Schl&uuml;ssel den Wert aus <b>strBenutzer <\/b>aufweist. Ist das der Fall, f&uuml;llt die Prozedur die <b>Recordset<\/b>-Variable <b>rstBenutzer <\/b>mit dem Eintrag der Tabelle <b>tblBenutzer<\/b>, dessen Benutzername mit dem Wert aus <b>strBenutzername <\/b>&uuml;bereinstimmt. Da wir die <b>Recordset<\/b>-Variable im allgemeinen Teil des Klassenmoduls deklariert haben, k&ouml;nnen wir nun von allen Prozeduren des Klassenmoduls aus darauf zugreifen.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>txtBenutzername_Change()\r\n     <span style=\"color:blue;\">Dim <\/span>strBenutzername<span style=\"color:blue;\"> As String<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     strBenutzername = Me!txtBenutzername.Text\r\n     <span style=\"color:blue;\">If <\/span>dicBenutzer.Exists(strBenutzername)<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n         <span style=\"color:blue;\">Set<\/span> rstBenutzer = db.OpenRecordset(\"SELECT * FROM tblBenutzer WHERE Benutzername = ''\" & strBenutzername _\r\n             & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">End If<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 3: Ereignisprozedur Bei &Auml;nderung des Textfeldes txtBenutzername<\/span><\/b><\/p>\n<h2>Das Zeitgeber-Ereignis<\/h2>\n<p>Damit kommen wir zu der Ereignisprozedur, die durch das Ereignis <b>Bei Zeitgeber <\/b>des Formulars ausgel&ouml;st werden soll und mit dem wir pr&uuml;fen wollen, ob die Anmeldung f&uuml;r den in <b>txtBenutzername<\/b> angegebenen Benutzer unterbunden werden muss, weil zu viele fehlgeschlagene Anmeldungen vorliegen. Die Prozedur finden Sie in Listing 4. Sie stellt zun&auml;chst die Eigenschaft <b>Painting <\/b>des Formulars auf den Wert <b>False<\/b>, um unn&ouml;tiges Flackern des Formulars zu verhindern.<\/p>\n<pre><span style=\"color:blue;\">Private Sub <\/span>Form_Timer()\r\n     <span style=\"color:blue;\">Dim <\/span>lngSekunden<span style=\"color:blue;\"> As Long<\/span>\r\n     Me.Painting = <span style=\"color:blue;\">False<\/span>\r\n     <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rstBenutzer Is Nothing<span style=\"color:blue;\"> Then<\/span>\r\n         <span style=\"color:blue;\">If <\/span><span style=\"color:blue;\">Not<\/span> rstBenutzer.EOF<span style=\"color:blue;\"> Then<\/span>\r\n             lngSekunden = DateDiff(\"s\", Now, DateAdd(\"s\", 2 ^ Nz(rstBenutzer!AnzahlFehlgeschlageneAnmeldungen, 0), _\r\n                 Nz(rstBenutzer!LetzteFehlgeschlageneAnmeldung, Date)))\r\n             <span style=\"color:blue;\">If <\/span>lngSekunden &gt; 0<span style=\"color:blue;\"> Then<\/span>\r\n                 <span style=\"color:blue;\">With<\/span> Me!lblNaechsteAnmeldung\r\n                     .Visible = <span style=\"color:blue;\">True<\/span>\r\n                     .Caption = \"N&auml;chste Anmeldung in \" & lngSekunden & \" Sekunden m&ouml;glich.\"\r\n                 End <span style=\"color:blue;\">With<\/span>\r\n                 Me!txtKennwort.Enabled = <span style=\"color:blue;\">False<\/span>\r\n                 Me!cmdAnmelden.Enabled = <span style=\"color:blue;\">False<\/span>\r\n             <span style=\"color:blue;\">Else<\/span>\r\n                 Me!lblNaechsteAnmeldung.Visible = <span style=\"color:blue;\">False<\/span>\r\n                 Me!txtKennwort.Enabled = <span style=\"color:blue;\">True<\/span>\r\n                 Me!cmdAnmelden.Enabled = <span style=\"color:blue;\">True<\/span>\r\n             <span style=\"color:blue;\">End If<\/span>\r\n         <span style=\"color:blue;\">Else<\/span>\r\n             Me!lblNaechsteAnmeldung.Visible = <span style=\"color:blue;\">False<\/span>\r\n             Me!txtKennwort.Enabled = <span style=\"color:blue;\">True<\/span>\r\n             Me!cmdAnmelden.Enabled = <span style=\"color:blue;\">True<\/span>\r\n         <span style=\"color:blue;\">End If<\/span>\r\n     <span style=\"color:blue;\">End If<\/span>\r\n     Me.Painting = <span style=\"color:blue;\">True<\/span>\r\n<span style=\"color:blue;\">End Sub<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 4: Ereignisprozedur Bei Zeitgeber<\/span><\/b><\/p>\n<p>Dann pr&uuml;ft sie, ob <b>rstBenutzer <\/b>&uuml;berhaupt schon gef&uuml;llt wurde, was ja erst geschieht, wenn der Benutzer einen g&uuml;ltigen Benutzernamen in das Textfeld <b>txtBenutzername <\/b>eingegeben hat. Ist das nicht der Fall, wird die Prozedur gleich wieder verlassen. Anderenfalls pr&uuml;ft die Prozedur, ob das Recordset einen Datensatz enth&auml;lt. Das ist wiederum der Fall, wenn <b>txtBenutzername <\/b>einen g&uuml;ltigen Benutzernamen enth&auml;lt. Ist auch das nicht der Fall, sollen die eventuell zuvor deaktivierten Steuer-elemente <b>lblNaechsteAnmeldung<\/b>, <b>txtKennwort <\/b>und <b>cmdAnmelden <\/b>wieder aktiviert werden.<\/p>\n<p>Das Bezeichnungsfeld <b>lblNaechsteAnmeldung<\/b> hatten wir noch gar nicht erw&auml;hnt &#8211; wir f&uuml;gen es wie in Bild 8 im Formular <b>frmAnmeldung <\/b>ein. Es dient der Ausgabe der Zeit bis zum n&auml;chsten Anmeldeversuch mit diesem Benutzernamen. Es soll nur eingeblendet werden, wenn ein g&uuml;ltiger Benutzername eingegeben wurde und der Benutzer so oft falsche Kennw&ouml;rter eingegeben hat, dass die Eingabe bis zum n&auml;chsten Versuch gesperrt wird.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_008.png\" alt=\"Anmeldedialog mit Hinweistext im Entwurf\" width=\"349,7625\" height=\"241,4604\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 8: Anmeldedialog mit Hinweistext im Entwurf<\/span><\/b><\/p>\n<p>Das geschieht nur, wenn die <b>If&#8230;Then<\/b>-Bedingung das Ergebnis wahr liefert. In diesem Fall ermittelt die Prozedur f&uuml;r die Variable <b>lngSekunden <\/b>die Anzahl der Sekunden, die bis zum n&auml;chsten Anmeldeversuch verstreichen m&uuml;ssen. Dazu verwenden wir zwei verschachtelte <b>DateDiff<\/b>&#8211; und <b>DateAdd<\/b>-Funktionen. Die innere <b>DateAdd<\/b>-Funktion soll dem Wert des Feldes <b>LetzteFehlgeschlageneAnmeldung <\/b>eine Anzahl von Sekunden hinzuf&uuml;gen, welche der Menge der fehlgeschlagenen Anmeldungen entspricht. Diese ermitteln wir &uuml;ber eine Potenz, deren Basis der Wert <b>2 <\/b>und deren Exponent der Anzahl der fehlgeschlagenen Anmeldungen aus dem Feld <b>AnzahlFehlgeschlageneAnmeldungen <\/b>entspricht.<\/p>\n<p>Die &auml;u&szlig;ere <b>DateDiff<\/b>-Funktion ermittelt die Differenz der Sekunden zwischen dem aktuellen Datum und dem Datum beziehungsweise Uhrzeit, an dem der n&auml;chste Anmeldeversuch m&ouml;glich ist. Ist der Wert aus <b>lngSekunden <\/b>gr&ouml;&szlig;er <b>0<\/b>, ist eine Wartezeit vorhanden und der Benutzer muss die ermittelte Anzahl Sekunden bis zum n&auml;chsten Anmeldeversuch warten. Deshalb blenden wir das Bezeichnungsfeld <b>lblNaechsteAnmeldung <\/b>ein und stellen die Beschriftung &uuml;ber die Eigenschaft <b>Caption <\/b>auf einen Text wie in Bild 9 ein. Au&szlig;erdem werden, wie ebenfalls in der Abbildung zu erkennen, die Steuer-elemente <b>txtKennwort <\/b>und <b>cmdAnmelden <\/b>deaktiviert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_009.png\" alt=\"Anmeldedialog mit Hinweistext\" width=\"349,7625\" height=\"241,4604\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 9: Anmeldedialog mit Hinweistext<\/span><\/b><\/p>\n<p>Das Steuer-element <b>cmdAbbrechen <\/b>bleibt aktiviert, damit der Benutzer die Anmeldung abbrechen und somit auch die Anwendung beenden kann. Das Textfeld <b>txtBenutzername <\/b>bleibt aktiviert, damit der Benutzer einen anderen Benutzernamen eingeben kann.<\/p>\n<p>Wenn <b>lngSekunden <\/b>kleiner oder gleich <b>0 <\/b>ist, kann der Benutzer gleich den n&auml;chsten Anmeldeversuch starten. Dazu blenden wir das Bezeichnungsfeld <b>lblNaechsteAnmeldung <\/b>wieder aus und aktivieren die beiden Steuer-elemente <b>cmdAnmelden <\/b>und <b>txtKennwort <\/b>wieder (siehe Bild 10). Am Ende der Prozedur stellen wir die Eigenschaft <b>Painting <\/b>wieder auf den Wert <b>True <\/b>ein, damit die vorgenommenen &Auml;nderungen am Formular sichtbar werden.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_010.png\" alt=\"Anmeldedialog, bereits zur Anmeldung\" width=\"349,7625\" height=\"241,4604\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 10: Anmeldedialog, bereits zur Anmeldung<\/span><\/b><\/p>\n<h2>Ermitteln, ob ein Benutzer Zugriff auf eine Tabelle hat<\/h2>\n<p>Wir ben&ouml;tigen noch eine Funktion, mit der wir herausfinden, ob ein bestimmter Benutzer Zugriff auf eine bestimmte Tabelle hat &#8211; und mit welchen Berechtigungen er auf die Tabelle zugreift. Dazu ziehen wir das Datenmodell von weiter oben heran und stellen eine Abfrage zusammen, die alle relevanten Tabellen enth&auml;lt. Diese Abfrage speichern wir unter dem Namen <b>qryBenutzerBerechtigungen<\/b>. Sie sieht im Entwurf wie in Bild 11 aus.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_011.png\" alt=\"Entwurf der Abfrage qryBenutzerBerechtigungen zum Ermitteln der Berechtigungen eines Benutzers an einer Tabelle\" width=\"700\" height=\"275,2953\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 11: Entwurf der Abfrage qryBenutzerBerechtigungen zum Ermitteln der Berechtigungen eines Benutzers an einer Tabelle<\/span><\/b><\/p>\n<p>Wechseln wir in die Datenblattansicht, erhalten wir ein Ergebnis wie in Bild 12. Wir werden allerdings nie mit der Datenblattansicht arbeiten, sondern eine Funktion erstellen, der wir die wichtigen Informationen wie den Benutzer und die Tabelle &uuml;bergeben und die uns dann die Berechtigungen f&uuml;r den Benutzer an der Tabelle zur&uuml;ckliefert.<\/p>\n<p class=\"image\"><img decoding=\"async\" src=\"..\/fileadmin\/_temp_\/2019_03\/pic_1192_012.png\" alt=\"Datenblattansicht der Abfrage qryBenutzerBerechtigungen\" width=\"549,6265\" height=\"282,6205\" \/><\/p>\n<p><b><span style=\"color:darkgrey;\">Bild 12: Datenblattansicht der Abfrage qryBenutzerBerechtigungen<\/span><\/b><\/p>\n<p>Diese Funktion hei&szlig;t <b>BenutzerBerechtigungen<\/b> und Sie finden diese in Listing 5. Die Funktion erwartet den Prim&auml;rschl&uuml;sselwert f&uuml;r den Benutzer sowie den Namen der zu untersuchenden Tabelle als Parameter. Sie liefert einen <b>Integer<\/b>-Wert zur&uuml;ck, der die Berechtigungen f&uuml;r den angegebenen Benutzer an dieser Tabelle repr&auml;sentiert.<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>BenutzerBerechtigungen(lngBenutzerID<span style=\"color:blue;\"> As Long<\/span>, strTabelle<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>intBerechtigungTemp<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT * FROM qryBenutzerBerechtigungen WHERE BenutzerID = \" & lngBenutzerID _\r\n         & \" AND Tabelle = ''\" & strTabelle & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         intBerechtigungTemp = intBerechtigungTemp + rst!BerechtigungID\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     BenutzerBerechtigungen = intBerechtigungTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 5: Funktion, um die Berechtigungen f&uuml;r einen Benutzer f&uuml;r eine bestimmte Tabelle zu ermitteln<\/span><\/b><\/p>\n<p>Die Funktion erstellt ein Recordset auf Basis der soeben definierten Abfrage <b>qryBenutzerBerechtigungen <\/b>und verwendet die Werte der Parameter <b>lngBenutzerID <\/b>und <b>strTabelle <\/b>als Vergleichswerte zweier Bedingungen. Dann durchl&auml;uft sie alle im Recordset enthaltenen Datens&auml;tze und addiert die Werte des Feldes <b>BerechtigungID <\/b>in einer <b>Do While<\/b>-Schleife. Die Summe gibt die Funktion dann als Ergebnis zur&uuml;ck. Wenn Sie die Funktion etwa vom Direktbereich aus aufrufen, erhalten Sie etwa das folgende Ergebnis:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> BenutzerBerechtigungen(2, \"tblArtikel\")\r\n15<\/pre>\n<p>Aber ist diese Berechnung &uuml;berhaupt korrekt Nein! Denn es kann ja sein, dass ein Benutzer Berechtigungen an einem Objekt &uuml;ber verschiedene Gruppenzuweisungen erh&auml;lt. Wenn er etwa in der Gruppe <b>Administratoren <\/b>ist und dar&uuml;ber die Rechte zum <b>Lesen<\/b>, <b>Anlegen<\/b>, <b>&Auml;ndern <\/b>und <b>Hinzuf&uuml;gen <\/b>besitzt und &uuml;ber die Gruppe <b>Bestellannahme <\/b>die Berechtigung zum Lesen, dann lautet der Wert nicht mehr <b>15 <\/b>(<b>1<\/b>+<b>2<\/b>+<b>4<\/b>+<b>8<\/b>), sondern <b>16 <\/b>(<b>1<\/b>+<b>2<\/b>+<b>4<\/b>+<b>8<\/b>+<b>1<\/b>). Wenn wir hier mit einem bin&auml;ren Vergleich ermitteln wollen, ob der Benutzer etwa die Berechtigung <b>Lesen <\/b>besitzt, die diesem ja hier gleich &uuml;ber zwei Gruppenzugeh&ouml;rigkeiten zugeteilt wurde, k&ouml;nnen wir diese nicht identifizieren. Bin&auml;r <b>1 <\/b>ist in bin&auml;r <b>15 <\/b>enthalten:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> (0001 AND 1111) = 0001 \r\n<span style=\"color:blue;\">True<\/span><\/pre>\n<p>Bin&auml;r <b>1 <\/b>ist aber nicht in bin&auml;r <b>16 <\/b>enthalten:<\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> (0001 AND 10000) = 0001\r\n<span style=\"color:blue;\">False<\/span><\/pre>\n<p>Wir m&uuml;ssen also einen Weg finden, &uuml;ber mehrere Benutzergruppen f&uuml;r einen Benutzer doppelt vergebene Berechtigungen nur einmal zu addieren. Wenn wir dies auf Basis der bereits erstellten Abfrage erledigen wollen, &auml;ndern wir die Funktion wie in Listing 6 ab. Dies liefert nun den korrekten Wert, auch wenn der Benutzer eine oder mehrere Berechtigungen &uuml;ber verschiedene Benutzergruppen mehrfach besitzt:<\/p>\n<pre><span style=\"color:blue;\">Public Function <\/span>BenutzerBerechtigungenEindeutig(lngBenutzerID<span style=\"color:blue;\"> As Long<\/span>, strTabelle<span style=\"color:blue;\"> As String<\/span>)<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Dim <\/span>db<span style=\"color:blue;\"> As <\/span>DAO.Database\r\n     <span style=\"color:blue;\">Dim <\/span>rst<span style=\"color:blue;\"> As <\/span>DAO.Recordset\r\n     <span style=\"color:blue;\">Dim <\/span>intBerechtigungTemp<span style=\"color:blue;\"> As Integer<\/span>\r\n     <span style=\"color:blue;\">Set<\/span> db = CurrentDb\r\n     <span style=\"color:blue;\">Set<\/span> rst = db.OpenRecordset(\"SELECT DISTINCT BerechtigungID FROM qryBenutzerBerechtigungen WHERE BenutzerID = \" _\r\n         & lngBenutzerID & \" AND Tabelle = ''\" & strTabelle & \"''\", dbOpenDynaset)\r\n     <span style=\"color:blue;\">Do While<\/span> <span style=\"color:blue;\">Not<\/span> rst.EOF\r\n         intBerechtigungTemp = intBerechtigungTemp + rst!BerechtigungID\r\n         rst.Move<span style=\"color:blue;\">Next<\/span>\r\n     <span style=\"color:blue;\">Loop<\/span>\r\n     BenutzerBerechtigungenEindeutig = intBerechtigungTemp\r\n<span style=\"color:blue;\">End Function<\/span><\/pre>\n<p><b><span style=\"color:darkgrey;\">Listing 6: Funktion, um die Berechtigungen f&uuml;r einen Benutzer f&uuml;r eine bestimmte Tabelle eindeutig zu ermitteln<\/span><\/b><\/p>\n<pre><span style=\"color:blue;\">Debug.Print<\/span> BenutzerBerechtigungenEindeutig(2,  \"tblBenutzerBenutzergruppen\")\r\n  15 <\/pre>\n<p>Der wesentliche Unterschied in der Programmierung ist die Verwendung des Schl&uuml;sselwort <b>DISTINCT <\/b>in der <b>SELECT<\/b>-Anweisung. Au&szlig;erdem haben wir die zur&uuml;ckzugebenden Felder auf <b>BerechtigungID <\/b>begrenzt.<\/p>\n<h2>Zusammenfassung und Ausblick<\/h2>\n<p>Mit dieser Funktion k&ouml;nnen Sie ermitteln, welche Berechtigungen ein Benutzer f&uuml;r die Daten einer Tabelle hat. Diese nutzen Sie dann in Formularen et cetera, um Daten gegebenenfalls schreibgesch&uuml;tzt darzustellen oder die Formulare erst gar nicht zu &ouml;ffnen.<\/p>\n<h3>Downloads zu diesem Beitrag<\/h3>\n<p>Enthaltene Beispieldateien:<\/p>\n<p>BenutzerUndBerechtigungenErmitteln.accdb<\/p>\n<p><a href=\"..\/fileadmin\/beispiele\/F338AD74-B77C-4E00-AE19-A7FD9E880817\/aiu_1192.zip\">Download<\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>In den Beitr&auml;gen &#8222;Benutzerverwaltung mit verschl&uuml;sselten Kennw&ouml;rtern&#8220; und &#8222;Berechtigungen per HTML verwalten&#8220; haben wir die Voraussetzungen f&uuml;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&szlig;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.<\/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":[662019,66032019,44000038],"tags":[],"class_list":["post-55001192","post","type-post","status-publish","format-standard","hentry","category-662019","category-66032019","category-Sicherheit"],"yoast_head":"<!-- This site is optimized with the Yoast SEO Premium plugin v20.9 (Yoast SEO v27.4) - https:\/\/yoast.com\/product\/yoast-seo-premium-wordpress\/ -->\n<title>Benutzer und Berechtigungen ermitteln - 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\/Benutzer_und_Berechtigungen_ermitteln\/\" \/>\n<meta property=\"og:locale\" content=\"de_DE\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Benutzer und Berechtigungen ermitteln\" \/>\n<meta property=\"og:description\" content=\"In den Beitr&auml;gen &quot;Benutzerverwaltung mit verschl&uuml;sselten Kennw&ouml;rtern&quot; und &quot;Berechtigungen per HTML verwalten&quot; haben wir die Voraussetzungen f&uuml;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&szlig;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.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/\" \/>\n<meta property=\"og:site_name\" content=\"Access im Unternehmen\" \/>\n<meta property=\"article:published_time\" content=\"2020-05-13T20:55:00+00:00\" \/>\n<meta property=\"og:image\" content=\"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5\" \/>\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=\"21\u00a0Minuten\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/\"},\"author\":{\"name\":\"Andr\u00e9 Minhorst\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#\\\/schema\\\/person\\\/13395c4bcd7d7963efe33be9c584d93f\"},\"headline\":\"Benutzer und Berechtigungen ermitteln\",\"datePublished\":\"2020-05-13T20:55:00+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/\"},\"wordCount\":3753,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5fe8a73c444c4e3089e66a67ee6fa0e5\",\"articleSection\":[\"2019\",\"3\\\/2019\",\"Sicherheit\"],\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/\",\"url\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/\",\"name\":\"Benutzer und Berechtigungen ermitteln - Access im Unternehmen\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#primaryimage\"},\"thumbnailUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5fe8a73c444c4e3089e66a67ee6fa0e5\",\"datePublished\":\"2020-05-13T20:55:00+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#breadcrumb\"},\"inLanguage\":\"de\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"de\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#primaryimage\",\"url\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5fe8a73c444c4e3089e66a67ee6fa0e5\",\"contentUrl\":\"http:\\\/\\\/vg06.met.vgwort.de\\\/na\\\/5fe8a73c444c4e3089e66a67ee6fa0e5\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/access-im-unternehmen.de\\\/Benutzer_und_Berechtigungen_ermitteln\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/access-im-unternehmen.de\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Benutzer und Berechtigungen ermitteln\"}]},{\"@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":"Benutzer und Berechtigungen ermitteln - 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\/Benutzer_und_Berechtigungen_ermitteln\/","og_locale":"de_DE","og_type":"article","og_title":"Benutzer und Berechtigungen ermitteln","og_description":"In den Beitr&auml;gen \"Benutzerverwaltung mit verschl&uuml;sselten Kennw&ouml;rtern\" und \"Berechtigungen per HTML verwalten\" haben wir die Voraussetzungen f&uuml;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&szlig;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.","og_url":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/","og_site_name":"Access im Unternehmen","article_published_time":"2020-05-13T20:55:00+00:00","og_image":[{"url":"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5","type":"","width":"","height":""}],"author":"Andr\u00e9 Minhorst","twitter_card":"summary_large_image","twitter_misc":{"Verfasst von":"Andr\u00e9 Minhorst","Gesch\u00e4tzte Lesezeit":"21\u00a0Minuten"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#article","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/"},"author":{"name":"Andr\u00e9 Minhorst","@id":"https:\/\/access-im-unternehmen.de\/#\/schema\/person\/13395c4bcd7d7963efe33be9c584d93f"},"headline":"Benutzer und Berechtigungen ermitteln","datePublished":"2020-05-13T20:55:00+00:00","mainEntityOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/"},"wordCount":3753,"commentCount":0,"publisher":{"@id":"https:\/\/access-im-unternehmen.de\/#organization"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5","articleSection":["2019","3\/2019","Sicherheit"],"inLanguage":"de","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/","url":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/","name":"Benutzer und Berechtigungen ermitteln - Access im Unternehmen","isPartOf":{"@id":"https:\/\/access-im-unternehmen.de\/#website"},"primaryImageOfPage":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#primaryimage"},"image":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#primaryimage"},"thumbnailUrl":"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5","datePublished":"2020-05-13T20:55:00+00:00","breadcrumb":{"@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#breadcrumb"},"inLanguage":"de","potentialAction":[{"@type":"ReadAction","target":["https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/"]}]},{"@type":"ImageObject","inLanguage":"de","@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#primaryimage","url":"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5","contentUrl":"http:\/\/vg06.met.vgwort.de\/na\/5fe8a73c444c4e3089e66a67ee6fa0e5"},{"@type":"BreadcrumbList","@id":"https:\/\/access-im-unternehmen.de\/Benutzer_und_Berechtigungen_ermitteln\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/access-im-unternehmen.de\/"},{"@type":"ListItem","position":2,"name":"Benutzer und Berechtigungen ermitteln"}]},{"@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\/55001192","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=55001192"}],"version-history":[{"count":0,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/posts\/55001192\/revisions"}],"wp:attachment":[{"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/media?parent=55001192"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/categories?post=55001192"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/access-im-unternehmen.de\/data\/wp\/v2\/tags?post=55001192"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}