Arbeiten mit Benutzeridentitäten bei der Authentifizierung in Azure App Service

In diesem Artikel wird gezeigt, wie Sie Benutzeridentitäten verwenden können, wenn Sie die integrierte Authentifizierung und Autorisierung in App Service nutzen.

Zugreifen auf Benutzeransprüche in App-Code

App Service stellt Ihrem Code für alle Sprachenframeworks die Ansprüche im eingehenden Token (ob dieses von einem authentifizierten Endbenutzer oder einer Clientanwendung stammt) zur Verfügung, indem sie in die Anforderungsheader eingefügt werden. Externe Anforderungen sind nicht zum Festlegen dieser Header berechtigt, sie sind also nur vorhanden, wenn sie von App Service festgelegt wurden. Beispiele für solche Header wären etwa:

Header Beschreibung
X-MS-CLIENT-PRINCIPAL Eine Base64-codierte JSON-Darstellung verfügbarer Ansprüche. Weitere Informationen finden Sie unter Decodieren des Clientprinzipalheaders.
X-MS-CLIENT-PRINCIPAL-ID Ein vom Identitätsanbieter festgelegter Bezeichner für den Aufrufer.
X-MS-CLIENT-PRINCIPAL-NAME Ein lesbarer Name für den vom Identitätsanbieter festgelegten Aufrufer, z. B. E-Mail-Adresse, Benutzerprinzipalname.
X-MS-CLIENT-PRINCIPAL-IDP Der Name des Identitätsanbieters, der von der App Service-Authentifizierung verwendet wird.

Anbietertoken werden auch über ähnliche Header verfügbar gemacht. Der Microsoft-Identitätsanbieter legt z. B. auch X-MS-TOKEN-AAD-ACCESS-TOKEN und X-MS-TOKEN-AAD-ID-TOKEN entsprechend fest.

Hinweis

Verschiedene Sprachenframeworks zeigen diese Header im App-Code möglicherweise in verschiedenen Formaten an (klein geschrieben oder mit großen Anfangsbuchstaben).

Anhand dieser Header kann jeder Code unabhängig von Programmiersprache oder Framework die benötigten Informationen ermitteln. Dieser Prozess wird in Decodieren des Clientprinzipalheaders behandelt. Für einige Frameworks bietet die Plattform außerdem weitere Optionen, die möglicherweise bequemer sind.

Decodieren des Clientprinzipalheaders

X-MS-CLIENT-PRINCIPAL enthält den vollständigen Satz verfügbarer Ansprüche als Base64-codiertes JSON. Diese Ansprüche durchlaufen einen Standardprozess der Anspruchszuordnung, sodass einige möglicherweise andere Namen haben als bei der direkten Verarbeitung des Tokens angezeigt würden. Die decodierten Nutzdaten sind wie folgt strukturiert:

{
    "auth_typ": "",
    "claims": [
        {
            "typ": "",
            "val": ""
        }
    ],
    "name_typ": "",
    "role_typ": ""
}
Eigenschaft Typ Beschreibung
auth_typ Zeichenfolge Der Name des Identitätsanbieters, der von der App Service-Authentifizierung verwendet wird.
claims Array von Objekten Ein Array von Objekten, die die verfügbaren Ansprüche darstellen. Jedes Objekt enthält die Eigenschaften typ und val.
typ Zeichenfolge Der Name des Anspruchs. Dieser wurde möglicherweise der Standardanspruchszuordnung unterzogen und könnte vom entsprechenden, in einem Token enthaltenen Anspruch abweichen.
val Zeichenfolge Der Wert des Anspruchs.
name_typ Zeichenfolge Der Anspruchstyp „Name“, bei dem es sich in der Regel um einen URI handelt, der Schemainformationen zu dem name-Anspruch bereitstellt, sofern einer definiert ist.
role_typ Zeichenfolge Der Anspruchstyp „Rolle“, bei dem es sich in der Regel um einen URI handelt, der Schemainformationen zu dem role-Anspruch bereitstellt, sofern einer definiert ist.

Zum Verarbeiten dieses Headers muss Ihre App die Nutzdaten decodieren und das claims-Array durchlaufen, um die relevanten Ansprüche zu finden. Es kann bequemer sein, diese in eine Darstellung zu konvertieren, die vom Sprachframework der App verwendet wird. Hier sehen Sie ein Beispiel für diesen Prozess in C#, der einen ClaimsPrincipal-Typ für die zu verwendende App erzeugt:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Claims;
using System.Text;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Http;

public static class ClaimsPrincipalParser
{
    private class ClientPrincipalClaim
    {
        [JsonPropertyName("typ")]
        public string Type { get; set; }
        [JsonPropertyName("val")]
        public string Value { get; set; }
    }

    private class ClientPrincipal
    {
        [JsonPropertyName("auth_typ")]
        public string IdentityProvider { get; set; }
        [JsonPropertyName("name_typ")]
        public string NameClaimType { get; set; }
        [JsonPropertyName("role_typ")]
        public string RoleClaimType { get; set; }
        [JsonPropertyName("claims")]
        public IEnumerable<ClientPrincipalClaim> Claims { get; set; }
    }

    public static ClaimsPrincipal Parse(HttpRequest req)
    {
        var principal = new ClientPrincipal();

        if (req.Headers.TryGetValue("x-ms-client-principal", out var header))
        {
            var data = header[0];
            var decoded = Convert.FromBase64String(data);
            var json = Encoding.UTF8.GetString(decoded);
            principal = JsonSerializer.Deserialize<ClientPrincipal>(json, new JsonSerializerOptions { PropertyNameCaseInsensitive = true });
        }

        /** 
         *  At this point, the code can iterate through `principal.Claims` to
         *  check claims as part of validation. Alternatively, we can convert
         *  it into a standard object with which to perform those checks later
         *  in the request pipeline. That object can also be leveraged for 
         *  associating user data, etc. The rest of this function performs such
         *  a conversion to create a `ClaimsPrincipal` as might be used in 
         *  other .NET code.
         */

        var identity = new ClaimsIdentity(principal.IdentityProvider, principal.NameClaimType, principal.RoleClaimType);
        identity.AddClaims(principal.Claims.Select(c => new Claim(c.Type, c.Value)));
        
        return new ClaimsPrincipal(identity);
    }
}

Frameworkspezifische Alternativen

Für ASP.NET 4.6-Apps füllt App Service die ClaimsPrincipal.Current-Eigenschaft mit Ansprüchen des authentifizierten Benutzers, sodass Sie dem standardmäßigen .NET Codemuster einschließlich des [Authorize]-Attributs folgen können. Auf ähnliche Weise füllt App Service die _SERVER['REMOTE_USER']-Variable für PHP-Apps. Für Java-Apps sind die Ansprüche über das Tomcat-Servlet zugänglich.

Für Azure Functions wird ClaimsPrincipal.Current nicht für .NET Code aufgefüllt, Sie können die Benutzeransprüche jedoch weiterhin in den Anforderungsheadern finden oder das ClaimsPrincipal-Objekt aus dem Anforderungskontext oder selbst durch einen Bindungsparameter abrufen. Weitere Informationen finden Sie unter Arbeiten mit Clientidentitäten.

Für .NET Core unterstützt Microsoft.Identity.Web das Auffüllen des aktuellen Benutzers mit der App Service-Authentifizierung. Weitere Informationen finden Sie im Microsoft.Identity.Web-Wiki, oder sehen Sie sich eine Demonstration dazu in diesem Tutorial für eine Web-App, die auf Microsoft Graph zugreift, an.

Hinweis

Damit die Anspruchszuordnung funktioniert, müssen Sie den Tokenspeicher aktivieren.

Zugreifen auf Benutzeransprüche mithilfe der API

Wenn der Tokenspeicher für Ihre App aktiviert ist, können Sie auch weitere Details zum authentifizierten Benutzer abrufen, indem Sie /.auth/me aufrufen.

Nächste Schritte