Neuigkeiten:

Wenn ihr euch für eine gute Antwort bedanken möchtet, im entsprechenden Posting einfach den Knopf "sag Danke" drücken!

Mobiles Hauptmenü

FE & BE: User, der sich anmeldet erkennen, eintragen und bei Abmeldung austragen

Begonnen von Ben, Februar 11, 2013, 17:22:56

⏪ vorheriges - nächstes ⏩

Ben

Hallo liebe Forengemeinde!


als fortgeschrittener Excel-User wurde ich nun dazu verdonnert, eine Datenbank in Access aufzubauen.
Da die Datenbank zentral liegt und mehrere User gleichzeitig darauf zugreifen können sollen, habe ich mich in die Aufteilung von Front End und Back End entschieden. Soweit hoffentlich korrekt!  ::)
Zudem sollen bestimmte User mehr Formulare angezeigt bekommen, als andere User. Dazu habe ich eine Userverwaltung mit Berechtigungen aufgebaut, die beim Laden des Haupt-Navigationsformulars (nav_frm_Hauptformular) prüft, wer angemeldet ist, und dementsprechend diverse Navigationsschaltflächen gar nicht erst anzeigt. Sollte durch einen Fehler doch eine bestimmte Schaltfläche angezeigt werden, habe ich in den entsprechenden Unterformularen eine Berechtigungsprüfung per VBA eingebaut (Ereignisprozedur beim Laden), die ein Öffnen mit einer MsgBox abbricht, sollte der User nicht die nötige Berechtigung haben.

Und hier liegt auch mein Problem. In der Tabelle tbl_Benutzer wird beim Login vermerkt, wer sich eingeloggt hat (per Datenbank.Execute Update). Zudem wird die ID des angemeldeten Users in die Tabelle tbl_angemeldete_Benutzer eingetragen (Spalte Optionswert), sodass das FE jederzeit darauf zurückgreifen können sollte, wer gerade an diesem FE angemeldet ist. Dies ist die einzigste Tabelle, dich ich im FE habe. Ist das klug?  ???  Keine Ahnung, aber da hoffe ich auf Tipps von euch! Jedenfalls funktioniert es einwandfrei, solange nur ein User die Datenbank über das FE startet.

Nun zum richtigen Problem:
Meldet sich ein zweiter User an der Datenbank an (über das FE, dass auf seinem Rechner liegt oder über eine zweite Instanz von Access), hängt sich der Code, der hinter dem Loginformular / -button liegt auf. Und das ist schonmal falsch. Das sollte doch laufen, oder nicht? Und durch einen Klick auf Logout im Hauptformular sollte der User wieder abgemeldet werden.
Also, wie schaffe ich es, dass mehrere User sich gleichzeitig anmelden können und das FE weiß, wer vor dem Rechner sitzt? Vielleicht ist das Geschichtchen mit der tbl_angemeldete_Benutzer einfach nicht gut. Ich hoffe, ihr könnt mir da Tips geben!

Ich freue mich über Hilfestellung und lerne auch gerne dazu!  ;)

Vielen Dank euch!


Verwendete Access-Version: 2010

HINWEIS zur Anmeldung:
Der Admin hat den Benutzernamen Admin und das Kennwort welcome
User haben den Benutzernamen User1, User2 und User3 und jeweils das Kennwort welcome
Admin darf alles sehen, die Benutzer nur die Schaltfläche "Eigenes Profil".
Ist das Kennwort beim Anmelden das Kennwort welcome, so startet der Dialog zur Vergabe eines eigenen Kennworts.

[Anhang gelöscht durch Administrator]

Wurliwurm

Es gibt die Möglichkeit, im Client den Windows-Anmeldenamen (mit einer API-Funktion) zu lesen und damit aus dem Backend die entsprechende Berechtigung per SQL aus einer Tabelle zu holen. So etwas habe ich einmal schon gemacht und es gab nie Probleme.

Die explizite Tabelle mit den angemeldeten User im Backend ist deshalb unglücklich, weil bei Zwangstrennungen/Abstürzen des Clients der angemeldete Name in der Tabelle stehenbleibt.




Ben

Hallo Wurliwurm!


Vielen Dank für deine Erklärung!  :D
Hast du mir den Code-Schnippsel, den ich brauche, um den Windows-Anmeldenamen auszulesen?
Ist es richtig, wenn ich den Schnippsel dann beim Open-Ereignis einsetze?
Sollte der User-name dann gleich dem Windowsnamen sein?

Fragen über Fragen - aber auch nur, weil ich mich über Antworten freue!  ;D


Danke euch!
Gruß, Ben

Wurliwurm

Hallo Ben,

google mal mit: access benutzernamen auslesen
Ergebnis z.B. http://www.administrator.de/forum/access-user-und-computername-mit-vba-auslesen-75695.html

Im Prinzip kann man bei jedem Form_Open Ereignis folgendes aufrufen
1. Benutzernamen Windows holen
2. Mit diesem im Backend die Berechtigung per SQL lesen
-Falls die Berechtigung nicht passt, Form-Open abbrechen lassen

Am besten Schritte 1 und 2 in eine Funktion kapseln.

Der Username sollte dann der Windows-Benutzername sein oder zumindest ein Windows-Benutzername eindeutig einem Usernamen zuzuordnen sein (1 zu 1 oder n zu 1)

Ben

Hallo Wurliwurm!


Ich hab mir das mal angeschaut und auch ausprobiert. Herzliches Danke für deine Links!  ;D
Ist ja klasse, was mit diesen API-Funktionenen so geht.
Am brauchbarsten fand ich den Code unter folgendem Link: http://access.mvps.org/access/api/api0008.htm

Der hat nur einen Nachteil:
Das von mir angedachte Front-End soll auch auf verschiedenen Rechnern von der selben Person genutzt werden können - teilweise auch von Privaten Systemen, die keine Anmeldung an einem Netzwerk erfordern. Daher auch das Login-Formular. Eigentlich müsste ich dann ja alle Usernames der Rechner, an denen die Person sitzen kann, mit dem Username im Back-End verknüpfen, aber das können ja unendlich viele sein. Wenn ich das nicht mache, müssten sich die User ja einen Rechner aussuchen, an dem die Berechtigungsgeschichte klappt, weil das Back-End den Windows-Usernamen in den Usernamen der Datenbank umwandeln kann (per Beziehung n:1) ...

Anderer Lösungsansatz:
Kann ich den Login-Namen vielleicht irgendwo in meinem Hauptformular ablegen (ungebundenes Textfeld), und immer daraus lesen zur Berechtigungsabfrage? Dann ist es unabhängig davon, welcher User gerade am Netzwerk angemeldetet ist.


Danke für deine/eure Mühe und Verständis und Hilfestellung!
Herzliche Grüße, Benjamin

Wurliwurm

Daß der gleiche Mensch an den verschiedenen Clients sich mit vielen unterschiedlichen Usernamen anmeldet, halte ich jetzt aber spontan für lebensfremd. Außerdem geht es nicht um Anmeldung am Netz, sondern Anmeldung am PC: Jeder Windows-Rechner, auch der von Oma Trude, läuft unter einem Benutzer. Ich kann es mir nicht vorstellen daß einer sich an einem Rechner mit muellerh, am anderen sich mit hmueller und an einem drittem sich mit muellerhans anmeldet und so weiter.

Der Windows-Anmeldename ist auf jeden Fall eine sicherere Identifikation als in einem Access-Frontend etwas zu hinterlegen. Ein Frontend kann man einfach kopieren auf einen anderen Rechner.

Imsgesamt darf man nie vergessen, daß diese Frontend-Backend-Geschichte nicht besonders viel taugt, wenn Performance, Datenintegrität und Sicherheit wichtig sind. In einem Datenbankmanagement-System kann man genau zuordnen, welche Tabellen ein bestimmter User lesen oder schreiben darf und außerdem ein Logging der ngemeldeten User. Es gibt von MS einen kostenlosen SQL-Server, von Oracle eine kostenlose Version XE und MySQL ist völlig frei. Bevor Du also etwas zusammenfrickelst, was von Haus aus niemals wirklich sicher werden kann, würde ich überlegen, ein solches System einzusetzen.

Ben

Hallo Wurliwurm!

Danke für deine Antwort!
Ich meinte damit mehr, dass der User ja einmal an seinem PC sitzen kann, aber auch an dem seiner Frau (welche ohne den Anmeldedialog bei Windows) ja bestimmt einen anderen Usernamen hinterlegt hat, als er an seinem PC, oder irre ich da?
Mit dem Login-formular weiß ich ja dann immerhin, wer vor dem Rechner sitzt, oder?  ???

Bitte seid geduldig mit mir, wenn ich da einen Denkfehler habe. Bin gern zum Lernen bereit!  ;)

Danke euch!
Gruß, Ben

Wurliwurm

Zitat von: Ben am Februar 13, 2013, 10:55:19
Ich meinte damit mehr, dass der User ja einmal an seinem PC sitzen kann, aber auch an dem seiner Frau (welche ohne den Anmeldedialog bei Windows) ja bestimmt einen anderen Usernamen hinterlegt hat, als er an seinem PC, oder irre ich da?
Mit dem Login-formular weiß ich ja dann immerhin, wer vor dem Rechner sitzt, oder?  ???

Nein, das weißt Du nicht. Wenn sich Fritzchen nämlich das Frontend vom PC (mit dem fest eingebauten User) auf seinen PC kopiert, wirst Du das niemals herausfinden können.

Die echte Alternative ist m.E. nur ein Datenbanksystem mit eigenem Login.


Ben

Hallo Wurliwurm!

Weshalb gehst du von einem Festeingebauten User im Front-End aus?
Der im Login-Formular ausgewählte User sollte dann nach korrekter Anmeldung in das ungebundene Textfeld eingetragen werden. Beim Logout (nur über eine Schaltfläche möglich) soll der User aus dem Textfeld wieder entfernt werden.
Selbst wenn der User durch einen Fehler nicht entfernt wird, taucht beim nächsten Starten des Front-Ends wieder der Login-Dialog (Formular) auf, welches bei erfolgreicher Anmeldung das Textfeld mit dem gerade angemeldeten User überschreibt.

Denkfehler?
Gruß, Ben

Wurliwurm

Zitat von: Ben am Februar 13, 2013, 11:23:01
Der im Login-Formular ausgewählte User sollte dann nach korrekter Anmeldung in das ungebundene Textfeld eingetragen werden.

Okay, wenn der User nicht hart kodiert werden soll, dann kann er auch als globale Variable im Client während der Laufzeit gehalten werden. Dann muß er in keinem Formular gespeichert werden.

Sowas habe ich in einer Anwendung so gemacht: Das Anmeldeformular schreibt mittels einer globalen Routine setAngemeldeterUser(byval strUser as String) in eine private Variable in einem Modul. Ausgelesen wird diese Variable mit Public Function getAngemeldeterUser() as String. Dadurch, daß die Variable private in einem extra Modul ist und nur über die beiden Methoden erreichbar ist, ist sie etwas besser vor unbeachsichtigten Überschreiben geschützt.

Ben

Das werd ich mal probieren.

Vielen Dank für deine Hilfe!
Kannst du mir bitte noch kurz Hilfestellung geben, wie ich diese globale Routine erstelle? (setAngemeldeterUser(byval strUser as String))
Das müsste so gehen, oder?
setAngemeldeterUser(byval strUser as String)
strUser = Forms!frm_login.cboBenutzer

Ist das dann ein Private Sub oder eine Funktion?
Wie ich die Auslesen kann, hast du mir ja netterweise schon geschrieben. Das müsste ich hinbekommen.

Vielen vielen Dank dir!

Gruß, Ben

Wurliwurm

Das Modul muß so aussehen

Option Explicit
Private strAngemeldeterUser as String

Public Sub setAngemeldeterUser(ByVal strUser as String)
   strAngemeldeterUser = strUser
End Sub

Public Function getAngemeldeterUser() As String
   getAngemeldeterUser = strAngemeldeterUser
End Sub


Im Formular wird so aufgerufen

Call setAngemeldeterUser(cboBenutzer.Value)

Es wird direkt aus dem Formular an das Sub übergeben.

Vielen Spaß noch und gern geschehen.

Stapi

Hallo Ben

Auf der einen Seite möchtest du das sich User anmelden und daraus Berechtigungen ableiten, das ist soweit OK. Nur wie @Wurliwurm schon angemerkt hat meldet sich im Normalfall der User an einem andren Rechner mit seiner kennung und Passwort an, somit steht zweifelsfrei  immer fest welcher User aktuell deine Anwendung benutzt.

Lege ein neues Modul an und füge folgene Code ein.
Option Compare Database
Option Explicit
Public Declare Function api_GetUserName Lib "advapi32.dll" Alias _
    "GetUserNameA" (ByVal lpBuffer As String, nSize As Long) As Long

Public Function atCNames() As String
    ' Ermittelt den Windows USERNAME
    Dim NBuffer As String
    Dim Buffsize As Long
    Dim Wok As Long
    Dim Temp As String
   
    Buffsize = 256
    NBuffer = Space$(Buffsize)
    Wok = api_GetUserName(NBuffer, Buffsize)
    Temp = Trim$(NBuffer)
    atCNames = Left(Temp, Len(Temp) - 1)
End Function
Damit wir dir über die Funktion immer der Angemedete User zurück gegeben.
Grüße aus dem schönen NRW
Stefan

Wurliwurm

Zitat von: Stapi am Februar 13, 2013, 16:48:12
Nur wie @Wurliwurm schon angemerkt hat meldet sich im Normalfall der User an einem andren Rechner mit seiner kennung und Passwort an, somit steht zweifelsfrei  immer fest welcher User aktuell deine Anwendung benutzt.

Ich glaube, er will innerhalb einer Windows-Anmeldung verschiedene Leute sich einloggen lassen.

Ben

Hallo Stapi.

Wurliwurm hat recht. Und mit seinem Code funktioniert das auch echt sauber! Vielen Dank dafür!
Ein Problemchen hab ich noch: und zwar beim Auslesen des getAngemeldeterUser zur Verwendung in einer Querry, deren Ergebnis (nämlich die Daten des angemeldeten Users) in einem Formular dargestellt werden soll.
Im Form_Open des Formulars steht folgender Code:

Private Sub Form_Open(Cancel As Integer)
'Lädt die eigenen Benutzerdaten

   Dim db As DAO.Database
   Dim qdf As DAO.QueryDef
   Dim prm As DAO.Parameter
   Dim lngAngemeldeterUser As Long
   
   lngAngemeldeterUser = CLng(OptionLesen("CurrentUserID"))
   
   Set db = CurrentDb
   Set qdf = db.QueryDefs("qry_eigene_Benutzerdaten")
   Set prm = qdf.Parameters("prmAngemeldeterUser")
   prm.Value = lngAngemeldeterUser
   
End Sub


Hier noch der Code der Funktion OptionLesen:
Public Function OptionLesen(strOptionsname As String) As String
'Liest den aktuell angemeldeten Benutzer aus
   
   OptionLesen = Nz(CLng(getAngemeldeterUser), "")

End Function


Der Parameter "prmAngemeldeterUser" sollte doch sauber übergeben werden, oder nicht? Wenn ich ihn nach der Zeile lngAngemeldeterUser = CLng(OptionLesen("CurrentUserID"))
in einer MsgBox ausgeben lasse, wird er korrekt angezeigt. Aber er wird einfach nicht an die Abfrage übergeben. Stattdessen öffnet sich jedesmal eine Inputbox, in der ich die ID des User manuell eingeben muss. Der Parameter ist so in der Querry als Kriterium angegeben "[prmAngemeldeterUser]" (ohne Anführungszeichen).

Woran liegt das?

Vielen Dank!
Gruß, Ben

PS: Wenn ich die Funktion OptionLesen als Long deklariere, kommt bei der Ausführung des Codes Form_Open der Lauzeitfehler 13: Typen unverträglich.