Exemplarische Vorgehensweise: Implementieren von benutzerdefinierter Authentifizierung und Autorisierung (Visual Basic)
In dieser exemplarischen Vorgehensweise wird veranschaulicht, wie unter Verwendung von Klassen, die von IIdentity und IPrincipal abgeleitet sind, benutzerdefinierte Authentifizierung und Autorisierung implementiert werden können. Dabei wird auch erläutert, wie die Standardidentität des Threads der Anwendung (die Windows-Identität) geändert werden kann, indem My.User.CurrentPrincipal auf eine Instanz der Klasse festgelegt wird, die von IPrincipal abgeleitet ist. Die neuen Benutzerinformationen sind sofort über das My.User-Objekt verfügbar, das Informationen über die aktuelle Benutzeridentität zurückgibt.
Welcher Zugriff in Geschäftsanwendungen auf Daten oder Ressourcen gewährt wird, ist häufig von den Anmeldeinformationen eines Benutzers abhängig. Normalerweise überprüfen diese Anwendungen die Rolle eines Benutzers und gestatten gemäß dieser Rolle einen Ressourcenzugriff. Die Common Language Runtime unterstützt die rollenbasierte Autorisierung über ein Windows-Konto oder eine benutzerdefinierte Identität. Weitere Informationen finden Sie unter Rollenbasierte Sicherheit.
Erste Schritte
Richten Sie zu Beginn ein Projekt mit einem Hauptformular und einem Anmeldeformular ein, und konfigurieren Sie dieses für die Verwendung von benutzerdefinierter Authentifizierung.
So erstellen Sie die Beispielanwendung
Erstellen Sie ein neues Visual Basic-Windows-Anwendungsprojekt. Weitere Informationen finden Sie unter Gewusst wie: Erstellen eines neuen Windows Forms-Anwendungsprojekts.
Der Standardname des Hauptformulars ist Form1.
Klicken Sie im Menü Projekt auf Neues Element hinzufügen.
Wählen Sie die Vorlage Anmeldeformular aus, und klicken Sie auf Hinzufügen.
Der Standardname des Anmeldeformulars ist LoginForm1.
Klicken Sie im Menü Projekt auf Neues Element hinzufügen.
Wählen Sie die Vorlage Klasse aus, ändern Sie den Namen in SampleIIdentity, und klicken Sie dann auf Hinzufügen.
Klicken Sie im Menü Projekt auf Neues Element hinzufügen.
Wählen Sie die Vorlage Klasse aus, ändern Sie den Namen in SampleIPrincipal, und klicken Sie dann auf Hinzufügen.
Klicken Sie im Menü Projekt auf <Anwendungsname>-Eigenschaften.
Klicken Sie im Projekt-Designer auf die Registerkarte Anwendung aus.
Wählen Sie in der Dropdownliste Authentifizierungsmodus den Eintrag Anwendungsdefiniert.
So konfigurieren Sie das Hauptformular
Wechseln Sie zu Form1 im Formular-Designer.
Fügen Sie Form1 aus der Toolbox eine Schaltfläche hinzu.
Der Standardname der Schaltfläche lautet Button1.
Ändern Sie den Schaltflächentext in Authentifizieren.
Fügen Sie Form1 aus der Toolbox eine Bezeichnung hinzu.
Der Standardname der Bezeichnung lautet Label1.
Ändern Sie den Bezeichnungstext in eine leere Zeichenfolge.
Fügen Sie Form1 aus der Toolbox eine Bezeichnung hinzu.
Der Standardname der Bezeichnung lautet Label2.
Ändern Sie den Bezeichnungstext in eine leere Zeichenfolge.
Doppelklicken Sie auf Button1, um den Ereignishandler für das Click-Ereignis zu erstellen, und öffnen Sie dann den Code-Editor.
Fügen Sie der Button1_Click-Methode folgenden Code hinzu:
My.Forms.LoginForm1.ShowDialog() ' Check if the user was authenticated. If My.User.IsAuthenticated Then Me.Label1.Text = "Authenticated " & My.User.Name Else Me.Label1.Text = "User not authenticated" End If If My.User.IsInRole(ApplicationServices.BuiltInRole.Administrator) Then Me.Label2.Text = "User is an Administrator" Else Me.Label2.Text = "User is not an Administrator" End If
Da kein Code für die Authentifizierung vorhanden ist, kann die Anwendung zwar ausgeführt, aber kein Benutzer authentifiziert werden. Das Hinzufügen von Code für die Authentifizierung wird im folgenden Abschnitt erläutert.
Erstellen einer Identität
In .NET Framework werden als Grundlage für Authentifizierung und Autorisierung die IIdentity-Schnittstelle und die IPrincipal-Schnittstelle verwendet. Durch Implementierung dieser Schnittstellen können Sie benutzerdefinierte Benutzerauthentifizierung verwenden, wie in den folgenden Verfahren veranschaulicht.
So erstellen Sie eine Klasse, die IIdentity implementiert
Wählen Sie im Projektmappen-Explorer die Datei SampleIIdentity.vb aus.
Diese Klasse kapselt die Identität eines Benutzers.
Fügen Sie in der Zeile nach Public Class SampleIIdentity den folgenden Code hinzu, um von IIdentity zu erben.
Implements System.Security.Principal.IIdentity
Nach dem Hinzufügen des Codes und dem Drücken der EINGABETASTE werden vom Code-Editor die zu implementierenden Stubeigenschaften erstellt.
Fügen Sie private Felder für die Speicherung des Benutzernamens und eines Wertes hinzu, mit dem angegeben wird, ob der Benutzer authentifiziert ist.
Private nameValue As String Private authenticatedValue As Boolean Private roleValue As ApplicationServices.BuiltInRole
Geben Sie in der AuthenticationType-Eigenschaft den folgenden Code ein.
Die AuthenticationType-Eigenschaft muss eine Zeichenfolge zurückgeben, die den aktuellen Authentifizierungsmechanismus angibt.
In diesem Beispiel wird explizit angegebene Authentifizierung verwendet, daher lautet die Zeichenfolge "Benutzerdefinierte Authentifizierung". Beim Speichern der Benutzerauthentifizierungsdaten in einer SQL Server-Datenbank könnte der Wert z. B. "SqlDatenbank" lauten.
Return "Custom Authentication"
Geben Sie in der IsAuthenticated-Eigenschaft den folgenden Code ein.
Return authenticatedValue
Die IsAuthenticated-Eigenschaft muss einen Wert zurückgeben, der angibt, ob der Benutzer authentifiziert wurde.
Die Name-Eigenschaft muss den Namen des Benutzers zurückgeben, der dieser Identität zugeordnet ist.
Geben Sie in der Name-Eigenschaft den folgenden Code ein.
Return nameValue
Erstellen Sie eine Eigenschaft, die die Rolle des Benutzers zurückgibt.
Public ReadOnly Property Role() As ApplicationServices.BuiltInRole Get Return roleValue End Get End Property
Erstellen Sie eine Sub New-Methode, die die Klasse durch Authentifizierung des Benutzers initialisiert und anschließend den Benutzernamen und die Benutzerrolle auf Grundlage eines Namens und eines Kennworts festlegt.
Diese Methode ruft eine Methode mit dem Namen IsValidNameAndPassword auf, um zu ermitteln, ob die angegebene Kombination aus Benutzername und Kennwort gültig ist.
Public Sub New(ByVal name As String, ByVal password As String) ' The name is not case sensitive, but the password is. If IsValidNameAndPassword(name, password) Then nameValue = name authenticatedValue = True roleValue = ApplicationServices.BuiltInRole.Administrator Else nameValue = "" authenticatedValue = False roleValue = ApplicationServices.BuiltInRole.Guest End If End Sub
Erstellen Sie eine Methode mit dem Namen IsValidNameAndPassword, die überprüft, ob eine bestimmte Kombination aus Benutzername und Kennwort gültig ist.
Sicherheitshinweis Beim Authentifizierungsalgorithmus muss ein sicheres Verfahren zur Verarbeitung der Kennwörter verwendet werden. So sollte das Kennwort z. B. nicht in einem Klassenfeld gespeichert werden.
Speichern Sie Kennwörter nicht im System, um Sicherheitsprobleme zu vermeiden. Stattdessen könnten Sie den Hash für das Kennwort eines Benutzers speichern. (Eine Hashfunktion verschlüsselt Daten, damit aus der Ausgabe nicht auf die Eingabe geschlossen werden kann.) Ein Kennwort kann nicht direkt aus dem zugehörigen Hashwert bestimmt werden.
Ein böswilliger Benutzer könnte eine Liste der Hashwerte aller möglichen Kennwörter generieren und anschließend das Kennwort für einen bestimmten Hashwert ermitteln. Um sich vor dieser Art von Angriffen zu schützen, sollten Sie das Kennwort vor dem Generieren des Hashwerts mit einer Salt kombinieren. Bei einer Salt handelt es sich um einen zusätzlichen Wert, der für jedes Kennwort eindeutig ist und so die Erstellung einer Hashliste unmöglich macht.
Speichern Sie grundsätzlich nur mit einer Salt erstellte Hashwerte von Kennwörtern, wenn möglich auf einem sicheren Computer, um Kennwörter vor böswilligen Benutzern zu schützen. Die Wiederherstellung eines Kennworts aus einem mit einer Salt erstellten Hashwert ist sehr schwierig. In diesem Beispiel werden die GetHashedPassword-Methode und die GetSalt-Methode verwendet, um das gehashte Kennwort und die Salt eines Benutzers zu laden.
Private Function IsValidNameAndPassword( ByVal username As String, ByVal password As String) As Boolean ' Look up the stored hashed password and salt for the username. Dim storedHashedPW As String = GetHashedPassword(username) Dim salt As String = GetSalt(username) 'Create the salted hash. Dim rawSalted As String = salt & Trim(password) Dim saltedPwBytes() As Byte = System.Text.Encoding.Unicode.GetBytes(rawSalted) Dim sha1 As New System.Security.Cryptography. SHA1CryptoServiceProvider Dim hashedPwBytes() As Byte = sha1.ComputeHash(saltedPwBytes) Dim hashedPw As String = Convert.ToBase64String(hashedPwBytes) ' Compare the hashed password with the stored password. Return hashedPw = storedHashedPW End Function
Erstellen Sie zwei Funktionen mit den Namen GetHashedPassword und GetSalt, die das gehashte Kennwort und die Salt für den angegebenen Benutzer zurückgeben.
Sicherheitshinweis Vermeiden Sie es aus zwei Gründen, die gehashten Kennwörter und die Salts in Clientanwendungen fest zu codieren. Zum einen könnten böswillige Benutzer darauf Zugriff erlangen und einen Hashkonflikt entdecken. Zum anderen können Sie das Kennwort eines Benutzers bei dieser Vorgehensweise nicht ändern oder widerrufen. Stattdessen sollten das gehashte Kennwort und die Salt für einen bestimmten Benutzer aus einer sicheren Quelle abgerufen werden, die von einem Administrator verwaltet wird.
In diesem Beispiel werden zur Vereinfachung fest codierte Werte für das gehashte Kennwort und die Salt eingesetzt. Verwenden Sie beim Erstellen von Productionscode jedoch ein sichereres Verfahren. So könnten Sie die Benutzerinformationen z. B. in einer SQL Server-Datenbank speichern und mit gespeicherten Prozeduren darauf zugreifen. Weitere Informationen finden Sie unter Gewusst wie: Herstellen einer Verbindung zu Daten in einer Datenbank.
Tipp
Das Kennwort, das diesem fest codierten Hashkennwort entspricht, finden Sie im Abschnitt "Testen der Anwendung".
Private Function GetHashedPassword(ByVal username As String) As String ' Code that gets the user's hashed password goes here. ' This example uses a hard-coded hashed passcode. ' In general, the hashed passcode should be stored ' outside of the application. If Trim(username).ToLower = "testuser" Then Return "ZFFzgfsGjgtmExzWBRmZI5S4w6o=" Else Return "" End If End Function Private Function GetSalt(ByVal username As String) As String ' Code that gets the user's salt goes here. ' This example uses a hard-coded salt. ' In general, the salt should be stored ' outside of the application. If Trim(username).ToLower = "testuser" Then Return "Should be a different random value for each user" Else Return "" End If End Function
Die Datei SampleIIdentity.vb sollte jetzt den folgenden Code enthalten:
Public Class SampleIIdentity
Implements System.Security.Principal.IIdentity
Private nameValue As String
Private authenticatedValue As Boolean
Private roleValue As ApplicationServices.BuiltInRole
Public ReadOnly Property AuthenticationType() As String Implements System.Security.Principal.IIdentity.AuthenticationType
Get
Return "Custom Authentication"
End Get
End Property
Public ReadOnly Property IsAuthenticated() As Boolean Implements System.Security.Principal.IIdentity.IsAuthenticated
Get
Return authenticatedValue
End Get
End Property
Public ReadOnly Property Name() As String Implements System.Security.Principal.IIdentity.Name
Get
Return nameValue
End Get
End Property
Public ReadOnly Property Role() As ApplicationServices.BuiltInRole
Get
Return roleValue
End Get
End Property
Public Sub New(ByVal name As String, ByVal password As String)
' The name is not case sensitive, but the password is.
If IsValidNameAndPassword(name, password) Then
nameValue = name
authenticatedValue = True
roleValue = ApplicationServices.BuiltInRole.Administrator
Else
nameValue = ""
authenticatedValue = False
roleValue = ApplicationServices.BuiltInRole.Guest
End If
End Sub
Private Function IsValidNameAndPassword(
ByVal username As String,
ByVal password As String) As Boolean
' Look up the stored hashed password and salt for the username.
Dim storedHashedPW As String = GetHashedPassword(username)
Dim salt As String = GetSalt(username)
'Create the salted hash.
Dim rawSalted As String = salt & Trim(password)
Dim saltedPwBytes() As Byte =
System.Text.Encoding.Unicode.GetBytes(rawSalted)
Dim sha1 As New System.Security.Cryptography.
SHA1CryptoServiceProvider
Dim hashedPwBytes() As Byte = sha1.ComputeHash(saltedPwBytes)
Dim hashedPw As String = Convert.ToBase64String(hashedPwBytes)
' Compare the hashed password with the stored password.
Return hashedPw = storedHashedPW
End Function
Private Function GetHashedPassword(ByVal username As String) As String
' Code that gets the user's hashed password goes here.
' This example uses a hard-coded hashed passcode.
' In general, the hashed passcode should be stored
' outside of the application.
If Trim(username).ToLower = "testuser" Then
Return "ZFFzgfsGjgtmExzWBRmZI5S4w6o="
Else
Return ""
End If
End Function
Private Function GetSalt(ByVal username As String) As String
' Code that gets the user's salt goes here.
' This example uses a hard-coded salt.
' In general, the salt should be stored
' outside of the application.
If Trim(username).ToLower = "testuser" Then
Return "Should be a different random value for each user"
Else
Return ""
End If
End Function
End Class
Erstellen eines Principals
Als nächstes müssen Sie eine Klasse implementieren, die von IPrincipal abgeleitet ist. Diese Klasse muss Instanzen der SampleIIdentity-Klasse zurückgeben.
So erstellen Sie eine Klasse, die IPrincipal implementiert
Wählen Sie im Projektmappen-Explorer die Datei SampleIPrincipal.vb aus.
Diese Klasse kapselt die Identität eines Benutzers. Sie können den Principal mithilfe des My.User-Objekts an den aktuellen Thread anfügen und auf die Identität des Benutzers zugreifen.
Fügen Sie in der Zeile nach Public Class SampleIPrincipal den folgenden Code hinzu, um von IPrincipal zu erben.
Implements System.Security.Principal.IPrincipal
Nach dem Hinzufügen des Codes und dem Drücken der EINGABETASTE werden vom Code-Editor eine Stubeigenschaft und eine Stubmethode erstellt, die von Ihnen implementiert werden müssen.
Fügen Sie ein privates Feld hinzu, um die diesem Principal zugeordnete Identität zu speichern.
Private identityValue As SampleIIdentity
Geben Sie in der Identity-Eigenschaft den folgenden Code ein.
Return identityValue
Die Identity-Eigenschaft muss die Benutzeridentität des aktuellen Principals zurückgeben.
Geben Sie in der IsInRole-Methode den folgenden Code ein.
Die IsInRole-Methode bestimmt, ob der aktuelle Principal zur angegebenen Rolle gehört.
Return role = identityValue.Role.ToString
Erstellen Sie eine Sub New-Methode, die die Klasse auf Grundlage eines Benutzernamens und Kennworts mit einer neuen Instanz von SampleIIdentity initialisiert.
Public Sub New(ByVal name As String, ByVal password As String) identityValue = New SampleIIdentity(name, password) End Sub
Mit diesem Code wird die Benutzeridentität für die SampleIPrincipal-Klasse festgelegt.
Die Datei SampleIPrincipal.vb sollte jetzt folgenden Code enthalten:
Public Class SampleIPrincipal
Implements System.Security.Principal.IPrincipal
Private identityValue As SampleIIdentity
Public ReadOnly Property Identity() As System.Security.Principal.IIdentity Implements System.Security.Principal.IPrincipal.Identity
Get
Return identityValue
End Get
End Property
Public Function IsInRole(ByVal role As String) As Boolean Implements System.Security.Principal.IPrincipal.IsInRole
Return role = identityValue.Role.ToString
End Function
Public Sub New(ByVal name As String, ByVal password As String)
identityValue = New SampleIIdentity(name, password)
End Sub
End Class
Verbinden des Anmeldeformulars
Mit dem Anmeldeformular kann ein Benutzername und ein Kennwort erfasst werden. Auf Grundlage dieser Informationen kann eine Instanz der SampleIPrincipal-Klasse initialisiert und mithilfe des My.User-Objekts die Identität des aktuellen Threads auf diese Instanz festgelegt werden.
So konfigurieren Sie das Anmeldeformular
Wählen Sie im Designer LoginForm1 aus.
Doppelklicken Sie auf die Schaltfläche OK, um den Code-Editor für das Click-Ereignis zu öffnen.
Ersetzen Sie den Code in der OK_Click-Methode durch den folgenden Code.
Dim samplePrincipal As New SampleIPrincipal( Me.UsernameTextBox.Text, Me.PasswordTextBox.Text) Me.PasswordTextBox.Text = "" If (Not samplePrincipal.Identity.IsAuthenticated) Then ' The user is still not validated. MsgBox("The username and password pair is incorrect") Else ' Update the current principal. My.User.CurrentPrincipal = samplePrincipal Me.Close() End If
Testen der Anwendung
Da die Anwendung jetzt Code für die Authentifizierung enthält, können Sie die Anwendung ausführen und die Benutzerauthentifizierung testen.
So testen Sie die Anwendung
Starten Sie die Anwendung.
Klicken Sie auf Authentifizieren.
Das Anmeldeformular wird geöffnet.
Geben Sie im Feld Benutzername den Text TestUser und im Feld Kennwort den Text BadPassword ein, und klicken Sie dann auf OK.
Es wird ein Meldungsfeld mit der Information angezeigt, dass die Kombination aus Benutzername und Kennwort ungültig ist.
Klicken Sie auf OK, um das Meldungsfeld zu schließen.
Klicken Sie auf Abbrechen, um das Anmeldeformular zu schließen.
Für die Bezeichnungen im Hauptformular wird jetzt Nicht authentifiziert und Kein Administrator angezeigt.
Klicken Sie auf Authentifizieren.
Das Anmeldeformular wird geöffnet.
Geben Sie im Feld Benutzername den Text TestUser und im Feld Kennwort den Text Password ein, und klicken Sie dann auf OK. Achten Sie beim Eingeben des Kennworts auf die korrekte Großschreibung.
Für die Bezeichnungen im Hauptformular wird jetzt Authentifizierter Testbenutzer und Kein Administrator angezeigt.
Siehe auch
Aufgaben
Gewusst wie: Herstellen einer Verbindung zu Daten in einer Datenbank
Referenz
Konzepte
Zugreifen auf Benutzerdaten (Visual Basic)
Weitere Ressourcen
Authentifizierung und Autorisierung in .NET Framework mit Visual Basic