In diesem Artikel möchte ich euch zeigen, wie man einen lokal gehosteten REST-Webservice mit Azure AD absichern kann. In diesem Beispiel zeige ich euch die Authentifizierung mit einem kleinen PowerShell Skript als Client, dass ein Zertifikat dafür verwendet.
Zuerst benötigen wir zwei App-Registrierungen in unserem Azure AD, eine für den REST-Webservice und eine für den Client (in diesem Fall PowerShell Skript).
Wir geben der App-Registrierung für unseren REST-Webservice einen entsprechend Namen, ansonsten müssen wir in diesem Schritt keine weiteren Anpassungen durchführen.
Nun erstellen wir eine neue App-Rolle, die für die Verwendung unseres Webservices notwendig ist.
Der Rolle geben wir einen aussagekräftigen Namen, Wert und Beschreibung. Ebenfalls definieren wir, dass Anwendungen die zulässigen Mitgliedstypen sind.
Nun müssen wir noch die Anwendungs-ID-URI erstellen bzw. festlegen.
Die vorgeschlagene App-ID-URI kann einfach übernommen, diese ist später für den Client relevant.
Nun sind wir mit dieser App-Registrierung fertig und können die App-Registrierung für den Client anlegen.
Dieser App-Registrierung geben wir ebenfalls einen aussagekräftigen Namen.
Nun fügen wir der App-Registrierung für den Client eine entsprechende API-Berechtigung für unsere App-Registrierung für unseren REST-Webservice hinzu.
Danach müssen wir die angeforderten Berechtigungen noch genehmigen.
Nun müssen wir das Zertifikat in der App-Registrierung noch hinterlegen, über das die Authentifizierung erfolgen soll. Wir exportieren also das Zertifikat ohne privaten Schlüssel und laden es in der App-Registrierung hoch.
Nach dem erfolgreichen Hochladen erscheint das Zertifikat mit einigen zusätzlichen Informationen in der Übersicht.
Nun haben wir alle Vorbereitungen getroffen und können nun den REST-Webservice mit Azure AD absichern.
In diesem Beispiel erstellen wir mit Visual Studio einfach ein neues ASP.NET Core-Web-API Projekt, dieses beinhaltet bereits einen Demo-Webservice, den wir nutzen können.
Dem Projekt geben wir ebenfalls einen entsprechenden Namen und lassen es uns erstellen.
Die weiteren Informationen können wir auf den Standard-Einstellungen belassen.
Zuerst passen wir die appsettings.json
Datei an, um die Konfiguration für unsere App-Registrierung zu hinterlegen. Die Informationen für den hinzuzufügenden AzureAD
Block finden wir in der Übersicht der App-Registrierung.
Hier noch einmal die appsettings.json
Datei zum kopieren. Die Werte müssen natürlich entsprechend angepasst werden.
{ "Logging": { "LogLevel": { "Default": "Information", "Microsoft.AspNetCore": "Warning" } }, "AllowedHosts": "*", "AzureAd": { "Instance": "https://login.microsoftonline.com/", "Domain": "M365x86804735.onmicrosoft.com", "TenantId": "b5e0c1a9-ebf0-4c5b-ae70-928f8a0cb5ba", "ClientId": "e32f813c-59d8-4d20-848b-8dbe4c0ac73e" } }
Nun müssen wir noch mit NuGet ein notwendiges Package herunterladen. Dabei handelt es sich um das Microsoft.Identity.Web
Package.
Nun müssen wir der Program.cs
noch die notwendige Authentifizierungsmethode hinzufügen. Das geschieht in der Zeile 9.
Hier noch einmal der gesamte Quellcode zum kopieren.
using Microsoft.Identity.Web; var builder = WebApplication.CreateBuilder(args); // Add services to the container. builder.Services.AddControllers(); // Add WebApiAuthentication builder.Services.AddMicrosoftIdentityWebApiAuthentication(builder.Configuration); // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle builder.Services.AddEndpointsApiExplorer(); builder.Services.AddSwaggerGen(); var app = builder.Build(); // Configure the HTTP request pipeline. if (app.Environment.IsDevelopment()) { app.UseSwagger(); app.UseSwaggerUI(); } app.UseHttpsRedirection(); // Add Authentication app.UseAuthentication(); app.UseAuthorization(); app.MapControllers(); app.Run();
Nun müssen wir nur noch unserem REST-Webservice das Authorize
Tag hinzufügen. Durch die ausgewählte Vorlage wurde uns der WeatherForecastController.cs
automatisch erstellt. Dort fügen wir in Zeile 9 das Tag mit der entsprechenden Rolle hinzu. Die Rolle muss natürlich der entsprechen, der wir in der App-Registrierung verwendet haben.
Und auch hier noch einmal der Quellcode zum kopieren.
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Mvc; using System.Data; namespace MyOwnRestService.Controllers { [ApiController] [Route("[controller]")] [Authorize(Roles = "OwnRestService.Use")] public class WeatherForecastController : ControllerBase { private static readonly string[] Summaries = new[] { "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching" }; private readonly ILogger<WeatherForecastController> _logger; public WeatherForecastController(ILogger<WeatherForecastController> logger) { _logger = logger; } [HttpGet(Name = "GetWeatherForecast")] public IEnumerable<WeatherForecast> Get() { return Enumerable.Range(1, 5).Select(index => new WeatherForecast { Date = DateTime.Now.AddDays(index), TemperatureC = Random.Shared.Next(-20, 55), Summary = Summaries[Random.Shared.Next(Summaries.Length)] }) .ToArray(); } } }
Wenn der REST-Webservice nun läuft, können wir uns um den Client kümmern.
Dafür erstellen wir ein kleines PowerShell Skript mit Hilfe des Az-Moduls.
Die Parameter in den Zeilen 3-6 müssen natürlich angepasst werden. $clientID
und $tenantID
erhalten wir aus der Übersicht der App-Registrierung für den Client. Die $resourceUrl
ist die App-ID-URI. Und $certThumbprint
ist der Thumbprint des zu verwendeten Zertifikats.
In Zeile 8 authentifizieren wir uns mit dem Zertifikat und nutzen den zurück gelieferten Token zur Authentifizierung an unserem lokalen REST-Webservice in Zeile 14.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 $clientID = "d7604f70-4e30-4e95-8d42-5bf04389ad63" $tenantID = "b5e0c1a9-ebf0-4c5b-ae70-928f8a0cb5ba" $resourceUrl = "api://e32f813c-59d8-4d20-848b-8dbe4c0ac73e" $certThumbprint = "5b0298e49578aae37571fb03dfe1a694abc09c89" Connect-AzAccount -CertificateThumbprint $certThumbprint -ApplicationId $clientID -Tenant $tenantID $azAccessToken = Get-AzAccessToken -ResourceUrl $resourceUrl $accessToken = $azAccessToken.Token $headers = @{Authorization = "Bearer $accessToken" } $contentType = 'application/json; charset=utf-8' Invoke-RestMethod -ContentType $contentType -Uri 'https://localhost:7281/WeatherForecast' -Method Get -Headers $headers -Body $json -UseBasicParsing
Der größte Aufwand ist die Konfiguration der notwendigen App-Registrierungen. Die Anpassungen im Code des Webservices sind sehr einfach und gering, weil die Unterstützung an dieser Stelle sehr gut von Microsoft ist.
Den kompletten Quellcode findet ihr auch in meinem GitHub Repository.
In diesem Sinne, Happy Coding 🙂