Das Konzept der verteilten Anwendungen wie mit z.B. Azure Functions als Serverless computing bezeichnet, hat es mir angetan. Besonders einfach ist es mit ASP.NET Web Api (egal ob Core oder .net framework). API Calls werden speziell im App to App Szenario meist mit einer ApplicationID Secret Kombination abgesichert. So ein Beispiel habe ich mit VB.NET implementiert um Datenaustausch zwischen zwei ASP.NET Webforms Anwendungen über Server grenzen hinweg, halbwegs sicher zu gestalten.
Im Kern wird in den HTTP Header beim Request (POST, GET …) ein zusätzlicher Key und Wert eingefügt. Bei mir schlicht X-ApiKey genannt.
1: Dim hc As New HttpClient()
2: hc.DefaultRequestHeaders.Add("X-ApiKey", "000000000")
3: ...
4: Dim ret = hc.DeleteAsync(New Uri("https://domain.de/api/booking/1111"
Der Artikel geht davon aus, das bekannt ist, wie ein API Controller (hier BookingController.vb) angelegt wird. Häufig sieht man das Attribut Authorize vor der Controller Klasse um eine Anmeldung zu erzwingen. Das bezieht sich aber auf einen Benutzer Prinzipal. Kann man per Code erstellen. Mein Weg ist einfacher mit einer Klasse geerbt von DelegatingHandler. Darin wird geprüft, ob ein Api Key im Header existiert und der Wert den Erwartungen entspricht. Andernfalls wird eine 403 Fehlermeldung zurückgegeben und die Ausführung in der Request Pipeline unterbrochen. Die Methode SendAsync (Zeile 18) leitet im Erfolgsfall an das nächste Modul in der HTTP Request Pipeline weiter.
1: Imports System.IdentityModel.Claims
2: Imports System.Net.Http
3: Imports System.Security.Claims
4: Imports System.Threading
5: Imports System.Threading.Tasks
6: Imports System.Web.Http
7: Imports System.Web.Http.Dispatcher
8: Imports Microsoft.VisualBasic
9:
10: Public Class AuthorizationApiKeyHandler
11: Inherits DelegatingHandler
12:
13: Protected Overrides Function SendAsync(request As HttpRequestMessage, cancellationToken As CancellationToken) As Task(Of HttpResponseMessage)
14: Dim apiKeyHeaderValues As IEnumerable(Of String)
15: If (request.Headers.TryGetValues("X-ApiKey", apiKeyHeaderValues)) Then
16: Dim apiKeyHeaderValue = apiKeyHeaderValues.First()
17: If apiKeyHeaderValue = "000000000" Then
18: Return MyBase.SendAsync(request, cancellationToken)
19: End If
20: End If
21:
22: Dim response = New HttpResponseMessage(Net.HttpStatusCode.Forbidden)
23: Dim tsc = New TaskCompletionSource(Of HttpResponseMessage)()
24: tsc.SetResult(response)
25: Return tsc.Task
26: End Function
27: End Class
Um nun die Klasse mit dem Controller zu verbinden, muss das Routing konfiguriert werden. Das passiert in der Datei WebApiConfig.vb. Diese sollte automatisch erstellt werden, wenn man in Visual Studio Projekt per Nuget die ASP.NET Web Api installiert.
Um für alle API Calls das neue Modul zu aktivieren, reicht eine Zeile Code, die den selbst geschriebenen Handler registriert.
1: config.MessageHandlers.Add(New AuthorizationApiKeyHandler())
Da aber viele API’s offen sein müssen um z.B. einer JavaScript Bibliothek einen CallBack zu erlauben, kommt ein selektiver Ansatz zum Einsatz. Obige Zeile wird nicht verwendet. Statt dessen wird spezifisch eine Route mit dem Authorization Handler als Parameter angelegt.
1: config.Routes.MapHttpRoute(
2: name:="DefaultApi",
3: routeTemplate:="api/{controller}/{id}",
4: defaults:=New With {.id = RouteParameter.Optional},
5: constraints:=Nothing,
6: handler:=New AuthorizationApiKeyHandler() With {.InnerHandler = New Dispatcher.HttpControllerDispatcher(config)}
7: )
Natürlich soll eine gesicherte verschlüsselte HTTPS Verbindung genutzt werden um den Key zu übertragen, analog zu Passwörtern. Mehr zu ASP.NET Web Api lernen Sie in unserem Training.