Share via


Exemplarische Vorgehensweise: Implementieren von benutzerdefinierter Authentifizierung und Autorisierung

Aktualisiert: November 2007

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

  1. Erstellen Sie ein neues Visual Basic-Windows-Anwendungsprojekt. Weitere Informationen finden Sie unter Gewusst wie: Erstellen eines Windows-Anwendungsprojekts.

    Der Standardname des Hauptformulars ist Form1.

  2. Klicken Sie im Menü Projekt auf Neues Element hinzufügen.

  3. Wählen Sie die Vorlage Anmeldeformular aus, und klicken Sie auf Hinzufügen.

    Der Standardname des Anmeldeformulars ist LoginForm1.

  4. Klicken Sie im Menü Projekt auf Neues Element hinzufügen.

  5. Wählen Sie die Vorlage Klasse aus, ändern Sie den Namen in SampleIIdentity, und klicken Sie dann auf Hinzufügen.

  6. Klicken Sie im Menü Projekt auf Neues Element hinzufügen.

  7. Wählen Sie die Vorlage Klasse aus, ändern Sie den Namen in SampleIPrincipal, und klicken Sie dann auf Hinzufügen.

  8. Klicken Sie im Menü Projekt auf <Anwendungsname>-Eigenschaften.

  9. Klicken Sie im Projekt-Designer auf die Registerkarte Anwendung aus.

  10. Wählen Sie in der Dropdownliste Authentifizierungsmodus den Eintrag Anwendungsdefiniert.

So konfigurieren Sie das Hauptformular

  1. Wechseln Sie zu Form1 im Formular-Designer.

  2. Fügen Sie Form1 aus der Toolbox eine Schaltfläche hinzu.

    Der Standardname der Schaltfläche lautet Button1.

  3. Ändern Sie den Schaltflächentext in Authentifizieren.

  4. Fügen Sie Form1 aus der Toolbox eine Bezeichnung hinzu.

    Der Standardname der Bezeichnung lautet Label1.

  5. Ändern Sie den Bezeichnungstext in eine leere Zeichenfolge.

  6. Fügen Sie Form1 aus der Toolbox eine Bezeichnung hinzu.

    Der Standardname der Bezeichnung lautet Label2.

  7. Ändern Sie den Bezeichnungstext in eine leere Zeichenfolge.

  8. Doppelklicken Sie auf Button1, um den Ereignishandler für das Click-Ereignis zu erstellen, und öffnen Sie dann den Code-Editor.

  9. 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

  1. Wählen Sie im Projektmappen-Explorer die Datei SampleIIdentity.vb aus.

    Diese Klasse kapselt die Identität eines Benutzers.

  2. 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.

  3. 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
    
  4. 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"
    
  5. 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.

  6. 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
    
  7. 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
    
  8. 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
    
  9. 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
    
  10. 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.

    Hinweis:

    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

  1. 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.

  2. 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.

  3. Fügen Sie ein privates Feld hinzu, um die diesem Principal zugeordnete Identität zu speichern.

    Private identityValue As SampleIIdentity
    
  4. Geben Sie in der Identity-Eigenschaft den folgenden Code ein.

    Return identityValue
    

    Die Identity-Eigenschaft muss die Benutzeridentität des aktuellen Principals zurückgeben.

  5. 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
    
  6. 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

  1. Wählen Sie im Designer LoginForm1 aus.

  2. Doppelklicken Sie auf die Schaltfläche OK, um den Code-Editor für das Click-Ereignis zu öffnen.

  3. 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

  1. Starten Sie die Anwendung.

  2. Klicken Sie auf Authentifizieren.

    Das Anmeldeformular wird geöffnet.

  3. 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.

  4. Klicken Sie auf OK, um das Meldungsfeld zu schließen.

  5. Klicken Sie auf Abbrechen, um das Anmeldeformular zu schließen.

    Für die Bezeichnungen im Hauptformular wird jetzt Nicht authentifiziert und Kein Administrator angezeigt.

  6. Klicken Sie auf Authentifizieren.

    Das Anmeldeformular wird geöffnet.

  7. 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

Konzepte

Zugreifen auf Benutzerdaten

Referenz

My.User-Objekt

IIdentity

IPrincipal

Weitere Ressourcen

Authentifizierung und Autorisierung in .NET Framework mit Visual Basic