ASP.NET Web API und Basic Authentifizierung über ASP.NET Membership

Die Anforderung ist eine neue REST API auf eine bestehende Anwendung aufzusetzen. Als Authentifizierung kommt das ASP.NET Membership System zum Einsatz. Microsoft hat in der Zwischenzeit einen neuen Provider DefaultMembershipProvider. Dieser ist für den Einsatz unter Azure geeignet und hat ein einfacheres Datenbankschema.

Ich verwende nach wie vor den AspNetSqlMembershipProvider. Dieser muss in der web.config konfiguriert werden. Die Nutzerdaten liegen in der Regel im SQL Server in der Datenbank aspnetdb.

Im IIS 7 muss die Basic Authentifizierung deaktiviert sein. In der Web.Config wird auf Custom Authentication umgestellt.

<authentication mode="None">

Im Controller wird dann die Authentifizierung des Requests per Attribut <Authorize> erzwungen.

<Authorize(Roles:="Users")>
    Public Function GetValues() As IEnumerable(Of String)
        Return New String() {"value1", "value2"}
  End Function

Das wird in der der Standard Einstellung leider die User Datenbank von Windows verwenden (oder AD). Ziel ist es aber in der Membership Datenbank die Benutzer zu verwalten.

Deswegen implementiere ich ein neues Attribut und schütze die komplette Controller Klasse vor unerlaubten Zugriff.

<myMembershipHttpAuthorize>
Public Class ValuesController
Inherits ApiController

Eine Klasse erbt von AuthorizeAttribut und überlädt die OnAuthorization Methode.

Die Benutzer Credentials werden bei Basic Anmeldung in der Form User : Passwort Base64 Codiert im Header des Request mitgeliefert. Entsprechend wird der Header genommen und soweit zerlegt um User und Passwort wieder daraus zu gewinnen. Wie immer der Hinweis das derartig übermittelte Account Daten zusätzlich geschützt werden müssen. Typischerweise mit https.

Dann wird letztendlich mit der Membership Klasse der Benutzer authentifiziert und das Security Token zugwiesen.

Public Class myMembershipHttpAuthorizeAttribute
Inherits AuthorizeAttribute
Public Overrides Sub OnAuthorization(ac As HttpActionContext)
If IsNothing(ac.Request.Headers.Authorization) Then
ac.Response =
New System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
Exit Sub
End If
Dim b64 As String = ac.Request.Headers.Authorization.Parameter
Dim decoded As String = Encoding.UTF8.GetString(Convert.FromBase64String(b64))
Dim user As String = Left(decoded, decoded.IndexOf(":"))
Dim password As String = decoded.Substring(decoded.IndexOf(":") + 1)
if Membership.Provider.ValidateUser(user, password) Then
Dim roles As String() = System.Web.Security.Roles.Provider.GetRolesForUser(user) Dim p As IPrincipal
p = New GenericPrincipal(New GenericIdentity(user), roles)
HttpContext.Current.User = p
Else
ac.Response =
New System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized)
End If


End Sub

Um das ganze zu testen, kann man Fiddler verwenden oder sich einen Test Client bauen. Hier der Code für einen Silverlight Client

  Dim wc As New WebClient()
  Dim encodedText = Convert.ToBase64String(Encoding.UTF8.GetBytes(user + ":" + pwd)
  wc.Headers("Authorization") = "Basic " & Convert.ToString(encodedText)
  AddHandler wc.DownloadStringCompleted, AddressOf wcCompleted
  wc.DownloadStringAsync(New Uri(
                  "http://localhost:14149/Api/Values", UriKind.Absolute))

Ich habe sehr viele Blogs zum Thema gelesen und mir auch die Lösung von Dominick Baier angesehen. Nach wie vor bin ich mir nicht sicher, ob diese Lösung die beste ist. Sie funktioniert, ist einfach und leicht anpassbar. Wer Feedback dazu hat, soll das hier einfach tun.

Pingbacks and trackbacks (1)+

Kommentare sind geschlossen