Teilen über


Microsoft Entra (ME-ID) Gruppen, Administrator-Rollen und App-Rollen (.NET 5 bis .NET 7)

Hinweis

Dies ist nicht die neueste Version dieses Artikels. Die aktuelle Version von ASP.NET Core finden Sie in der neuesten Version von ASP.NET Core Blazor WebAssembly mit Microsoft Entra ID-Gruppen und Rollen.

In diesem Artikel wird erläutert, wie Sie Blazor WebAssembly für die Verwendung von Microsoft Entra ID-Gruppen und -Rollen konfigurieren.

Microsoft Entra ID (ME-ID) bietet mehrere Autorisierungsansätze, die mit ASP.NET Core Identity kombiniert werden können:

  • Gruppen
    • Sicherheit
    • Microsoft 365
    • Verteilung
  • Rollen
    • ME-ID-Administratorrollen
    • App-Rollen

Die Hinweise in diesem Artikel gelten für die Blazor WebAssembly ME-ID Bereitstellungsszenarien, die in den folgenden Artikeln beschrieben werden:

Dieser Artikel enthält Anleitungen für Client- und Server-Apps:

  • CLIENT: Eigenständige Blazor WebAssembly-Apps oder die Client -App einer gehosteten BlazorProjektmappe.
  • SERVER: ASP.NET Core-Server-API-/Web-API-Apps oder die Server-App einer gehosteten Blazor-Lösung. Bei einer eigenständigen Blazor WebAssembly-App können Sie den Leitfaden SERVER in diesem Artikel ignorieren.

Die Beispiele in diesem Artikel nutzen neue .NET/C#-Funktionen. Wenn Sie die Beispiele mit .NET 7 oder früher verwenden, sind geringfügige Änderungen erforderlich. Die Text- und Codebeispiele, die sich auf die Interaktion mit ME-ID und Microsoft Graph beziehen, sind jedoch für alle Versionen von ASP.NET Core identisch.

Voraussetzung

Im Leitfaden in diesem Artikel wird die Microsoft Graph-API gemäß dem Leitfaden zum Graph SDK unter Verwenden der Graph-API mit der Blazor WebAssembly von ASP.NET Core implementiert. Konfigurieren und testen Sie die App gemäß dem Implementierungsleitfaden für das Graph SDK, um sicherzustellen, dass die App Graph-API-Daten für ein Testbenutzerkonto abrufen kann. Lesen Sie außerdem die Informationen zu den Sicherheitskonzepten von Microsoft Graph, die Sie unter den Querlinks im Artikel zur Sicherheit der Graph-API finden.

Beim lokalem Testen mit dem Graph SDK empfehlen wir die Verwendung einer neuen privaten bzw. Inkognito-Browsersitzung für jeden Test, um zu verhindern, dass Tests durch vorhandene Cookies beeinträchtigt werden. Weitere Informationen finden Sie unter Sichern einer eigenständigen ASP.NET Core-Blazor WebAssembly-App mit Microsoft Entra ID.

Bereiche

So lassen Sie Microsoft Graph-API-Aufrufe für Benutzerprofil-, Rollenzuweisungs- und Gruppenmitgliedschaftsdaten zu:

  • Eine CLIENT-App wird mit dem delegierten User.Read-Bereich (https://graph.microsoft.com/User.Read) im Azure-Portal konfiguriert, da der Zugriff auf das Lesen von Benutzerdaten durch die Bereiche bestimmt wird, die einzelnen Benutzern gewährt (delegiert) werden.
  • Eine SERVER-App wird mit dem GroupMember.Read.All-Bereich der Anwendung (https://graph.microsoft.com/GroupMember.Read.All) im Azure-Portal konfiguriert, da der Zugriff für die App für den Zugriff auf Informationen zur Gruppenmitgliedschaft gilt, nicht basierend auf der Autorisierung einzelner Benutzerinnen und Benutzer für den Zugriff auf Daten zu Gruppenmitgliedern.

Die vorstehenden Bereiche sind zusätzlich zu den Bereichen erforderlich, die in den ME-ID-Bereitstellungsszenarien benötigt werden, die in den zuvor aufgeführten Artikeln beschrieben sind (Standalone mit Microsoft-Konten, Standalone mit ME-ID und Gehostet mit ME-ID).

Weitere Informationen finden Sie in der Übersicht über Berechtigungen und Zustimmung in der Microsoft-Identitätsplattform und der Übersicht über Microsoft Graph-Berechtigungen.

Berechtigungen und Bereiche bedeuten dasselbe und werden in der Sicherheitsdokumentation und im Azure-Portal austauschbar verwendet. Sofern sich der Text nicht auf das Azure-Portal bezieht, verwendet dieser Artikel scope/scopes, wenn er sich auf Graph-Berechtigungen bezieht.

Die Groß- und Kleinschreibung spielt keine Rolle, also ist User.Read dasselbe wie user.read. Sie können beide Formate verwenden, aber wir empfehlen eine einheitliche Wahl für den gesamten Anwendungscode.

groupMembershipClaims-Attribut

Legen Sie im Azure-Portal im App-Manifest für CLIENT- und SERVER-Apps das groupMembershipClaims-Attribut auf DirectoryRole fest. Ein Wert von DirectoryRole führt dazu, dass ME-ID alle Rollen des angemeldeten Benutzers im Well-known IDs claim (wids) sendet:

  1. Öffnen Sie die Azure-Portal-Registrierung der App.
  2. Wählen Sie in der Randleiste Verwalten>Manifest aus.
  3. Suchen Sie das groupMembershipClaims-Attribut.
  4. Legen Sie den Wert auf DirectoryRole fest ("groupMembershipClaims": "DirectoryRole").
  5. Wählen Sie die Schaltfläche Speichern aus, wenn Sie Änderungen vorgenommen haben.

Legen Sie im Azure-Portal im App-Manifest für CLIENT- und SERVER-Apps das groupMembershipClaims-Attribut auf All fest. Beim Wert All sendet ME-ID alle Sicherheitsgruppen, Verteilergruppen und Rollen des angemeldeten Benutzers im Anspruch bekannter IDs (wids):

  1. Öffnen Sie die Azure-Portal-Registrierung der App.
  2. Wählen Sie in der Randleiste Verwalten>Manifest aus.
  3. Suchen Sie das groupMembershipClaims-Attribut.
  4. Legen Sie den Wert auf All fest ("groupMembershipClaims": "All").
  5. Wählen Sie die Schaltfläche Speichern aus, wenn Sie Änderungen vorgenommen haben.

Benutzerdefiniertes Benutzerkonto

Weisen Sie Benutzer im Azure-Portal zu ME-ID-Sicherheitsgruppen und ME-ID-Administratorrollen zu.

Für die Beispiele in diesem Artikel gilt:

  • Es wird angenommen, dass einem Benutzer im ME-ID-Mandanten im Azure-Portal die ME-ID-Rolle Abrechnungsadministrator zugewiesen ist, damit dieser Benutzer für den Zugriff auf die Zugriffsserver-API-Daten autorisiert ist.
  • Verwenden Sie Autorisierungsrichtlinien, um den Zugriff innerhalb der CLIENT- und SERVER-Apps zu steuern.

Erweitern Sie RemoteUserAccount in der CLIENT-App, um Eigenschaften für Folgendes einzuschließen:

CustomUserAccount.cs:

using System.Text.Json.Serialization;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

namespace BlazorSample;

public class CustomUserAccount : RemoteUserAccount
{
    [JsonPropertyName("roles")]
    public List<string>? Roles { get; set; }

    [JsonPropertyName("wids")]
    public List<string>? Wids { get; set; }

    [JsonPropertyName("oid")]
    public string? Oid { get; set; }
}

Fügen Sie einen Paketverweis zur CLIENT-App für Microsoft.Graph hinzu.

Hinweis

Eine Anleitung zum Hinzufügen von Paketen zu .NET-Anwendungen finden Sie in den Artikeln unter Pakete installieren und verwalten unter Workflow für die Paketnutzung (NuGet-Dokumentation). Überprüfen Sie unter NuGet.org, ob die richtige Paketversion verwendet wird.

Fügen Sie die Hilfsklassen des Graph SDK und die Konfiguration im Leitfaden zum Graph SDK im Artikel Verwenden der Graph-API mit der Blazor WebAssembly von ASP.NET Core hinzu. Geben Sie wie in der Beispieldatei wwwroot/appsettings.json im Artikel gezeigt den User.Read-Bereich für das Zugriffstoken an.

Fügen Sie der CLIENT-App die folgende benutzerdefinierte Benutzerkontofactory hinzu. Die benutzerdefinierte Benutzerfactory wird verwendet, um Folgendes einzurichten:

  • App-Rollenansprüche (appRole) (beschrieben im Abschnitt App-Rollen)
  • ME-ID-Administratorrollenansprüche (directoryRole).
  • Beispiel für Benutzerprofildaten-Ansprüche für die Mobiltelefonnummer (mobilePhone) und den Bürostandort (officeLocation) des Benutzers
  • ME-ID-Gruppenansprüche (directoryGroup).
  • Ein ILogger (logger) für den Fall, dass Sie Informationen oder Fehler protokollieren möchten

CustomAccountFactory.cs:

using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;
using Microsoft.Kiota.Abstractions.Authentication;

namespace BlazorSample;

public class CustomAccountFactory() 
    : AccountClaimsPrincipalFactory<CustomUserAccount>
{
    private readonly ILogger<CustomAccountFactory> logger;
    private readonly IServiceProvider serviceProvider;
    private readonly string? baseUrl =
        string.Join("/",
            config.GetSection("MicrosoftGraph")["BaseUrl"] ??
                "https://graph.microsoft.com",
            config.GetSection("MicrosoftGraph")["Version"] ??
                "v1.0");

    public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
        : base(accessor)
    {
        this.serviceProvider = serviceProvider;
        this.logger = logger;
    }

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null && !string.IsNullOrEmpty(baseUrl))
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

                try
                {
                    var client = new GraphServiceClient(
                        new HttpClient(),
                        serviceProvider
                            .GetRequiredService<IAuthenticationProvider>(),
                        baseUrl);

                    var user = await client.Me.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var graphGroups = await requestMemberOf.GraphGroup.GetAsync();

                    if (graphGroups?.Value is not null)
                    {
                        foreach (var entry in graphGroups.Value)
                        {
                            if (entry.Id is not null)
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}
using System.Security.Claims;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication;
using Microsoft.AspNetCore.Components.WebAssembly.Authentication.Internal;
using Microsoft.Graph;

namespace BlazorSample;

public class CustomAccountFactory() 
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger;
    private readonly IServiceProvider serviceProvider;

    public CustomAccountFactory(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
        : base(accessor)
    {
        this.serviceProvider = serviceProvider;
        this.logger = logger;
    }

    public override async ValueTask<ClaimsPrincipal> CreateUserAsync(
        CustomUserAccount account,
        RemoteAuthenticationUserOptions options)
    {
        var initialUser = await base.CreateUserAsync(account, options);

        if (initialUser.Identity is not null &&
            initialUser.Identity.IsAuthenticated)
        {
            var userIdentity = initialUser.Identity as ClaimsIdentity;

            if (userIdentity is not null)
            {
                account?.Roles?.ForEach((role) =>
                {
                    userIdentity.AddClaim(new Claim("appRole", role));
                });

                account?.Wids?.ForEach((wid) =>
                {
                    userIdentity.AddClaim(new Claim("directoryRole", wid));
                });

                try
                {
                    var client = ActivatorUtilities
                        .CreateInstance<GraphServiceClient>(serviceProvider);
                    var request = client.Me.Request();
                    var user = await request.GetAsync();

                    if (user is not null)
                    {
                        userIdentity.AddClaim(new Claim("mobilephone",
                            user.MobilePhone ?? "(000) 000-0000"));
                        userIdentity.AddClaim(new Claim("officelocation",
                            user.OfficeLocation ?? "Not set"));
                    }

                    var requestMemberOf = client.Users[account?.Oid].MemberOf;
                    var memberships = await requestMemberOf.Request().GetAsync();

                    if (memberships is not null)
                    {
                        foreach (var entry in memberships)
                        {
                            if (entry.ODataType == "#microsoft.graph.group")
                            {
                                userIdentity.AddClaim(
                                    new Claim("directoryGroup", entry.Id));
                            }
                        }
                    }
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }

        return initialUser;
    }
}

Der vorangehende Code enthält keine transitiven Mitgliedschaften. Wenn die App direkte und transitive Gruppenmitgliedschaftsansprüche erfordert, ersetzen Sie die MemberOf-Eigenschaft (IUserMemberOfCollectionWithReferencesRequestBuilder) durch TransitiveMemberOf (IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder).

Der vorangehende Code ignoriert Gruppenmitgliedschaftsansprüche (groups), die ME-ID Administratorrollen (#microsoft.graph.directoryRole Typ) sind, weil die von ME-ID zurückgegebenen GUID-Werte Administratorrollen Entitäts-IDs und nicht Rollen Template IDs sind. Entitäts-IDs sind nicht mandantenübergreifend stabil und sollten nicht zur Erstellung von Richtlinien für die Berechtigung von Benutzern in Apps verwendet werden. Verwenden Sie immer Vorlagen-IDs für ME-ID-Administrator-Rollen, die von wids-Ansprüchen bereitgestellt werden.

Der wids-Anspruch(und damit directoryRole-Forderung) mit einem Wert von b79fbf4d-3ef9-4689-8143-76b194e85509 existiert für Nicht-Gastkonten des Mandanten. Sie bezieht sich nicht auf eine ME-ID Administrator Role Vorlagen-ID.

Konfigurieren Sie in der CLIENT-App die MSAL-Authentifizierung (Microsoft Authentication Library) für die Verwendung der benutzerdefinierten Benutzerkontofactory.

Vergewissern Sie sich, dass die Datei Program den Microsoft.AspNetCore.Components.WebAssembly.Authentication-Namespace verwendet:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

Aktualisieren Sie den AddMsalAuthentication-Aufruf wie im Folgenden gezeigt. Beachten Sie, dass das RemoteUserAccount des Blazor-Frameworks durch das CustomUserAccount der App für die MSAL-Authentifizierung und die Kontoanspruchs-Prinzipalfactory ersetzt wird:

builder.Services.AddMsalAuthentication<RemoteAuthenticationState,
    CustomUserAccount>(options =>
    {
        builder.Configuration.Bind("AzureAd",
            options.ProviderOptions.Authentication);
    })
    .AddAccountClaimsPrincipalFactory<RemoteAuthenticationState, CustomUserAccount,
        CustomAccountFactory>();

Vergewissern Sie sich, dass der im Artikel Verwenden der Graph-API mit der Blazor WebAssembly von ASP.NET Core beschriebene Graph SDK-Code vorhanden ist und die Konfiguration von wwwroot/appsettings.json dem Leitfaden zum Graph SDK entspricht:

var baseUrl = 
    string.Join("/",
        builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"] ??
            "https://graph.microsoft.com",
        builder.Configuration.GetSection("MicrosoftGraph")["Version"] ??
            "v1.0");
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>() ?? [ "user.read" ];

builder.Services.AddGraphClient(baseUrl, scopes);

wwwroot/appsettings.json:

{
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com",
    "Version": "v1.0",
    "Scopes": [
      "user.read"
    ]
  }
}

Konfigurieren der Autorisierung

Erstellen Sie in der CLIENT-App eine Richtlinie für jede App-Rolle, ME-ID-Administratorrolle oder Sicherheitsgruppe in der Program-Datei. Das folgende Beispiel erstellt eine Richtlinie für die in ME-ID integrierte Rolle Billing Administrator:

builder.Services.AddAuthorizationCore(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("directoryRole", 
            "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

Die vollständige Liste der IDs für ME-ID Administratorrollen finden Sie unter Rollenvorlagen-IDs in der Entra-Dokumentation. Weitere Informationen zu Autorisierungsrichtlinien finden Sie unter Richtlinienbasierte Autorisierung in ASP.NET Core.

In den folgenden Beispielen verwendet die CLIENT-App die oben genannte Richtlinie zum Autorisieren des Benutzers.

Die AuthorizeView-Komponente verwendet die Richtlinie:

<AuthorizeView Policy="BillingAdministrator">
    <Authorized>
        <p>
            The user is in the 'Billing Administrator' ME-ID Administrator Role
            and can see this content.
        </p>
    </Authorized>
    <NotAuthorized>
        <p>
            The user is NOT in the 'Billing Administrator' role and sees this
            content.
        </p>
    </NotAuthorized>
</AuthorizeView>

Durch Verwendung einer [Authorize]-Attributanweisung (AuthorizeAttribute) kann mithilfe der Richtlinie der Zugriff auf eine gesamte Komponente geregelt werden:

@page "/"
@using Microsoft.AspNetCore.Authorization
@attribute [Authorize(Policy = "BillingAdministrator")]

Wenn der Benutzer nicht autorisiert ist, wird er zur ME-ID-Anmeldeseite umgeleitet.

Eine Richtlinienüberprüfung kann auch in Code mit prozeduraler Logik durchgeführt werden.

CheckPolicy.razor:

@page "/checkpolicy"
@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<h1>Check Policy</h1>

<p>This component checks a policy in code.</p>

<button @onclick="CheckPolicy">Check 'BillingAdministrator' policy</button>

<p>Policy Message: @policyMessage</p>

@code {
    private string policyMessage = "Check hasn't been made yet.";

    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task CheckPolicy()
    {
        var user = (await authenticationStateTask).User;

        if ((await AuthorizationService.AuthorizeAsync(user, 
            "BillingAdministrator")).Succeeded)
        {
            policyMessage = "Yes! The 'BillingAdministrator' policy is met.";
        }
        else
        {
            policyMessage = "No! 'BillingAdministrator' policy is NOT met.";
        }
    }
}

Mit den vorstehenden Ansätzen können Sie auch einen richtlinienbasierten Zugriff für App-Rollen erstellen, wobei die für die Richtlinie verwendete GUID im appRoles-Element des Manifests der App im Azure-Portal festgelegt wird, sowie für Sicherheitsgruppen, wobei die für die Richtlinie verwendete GUID mit der Gruppe Objekt-ID im Bereich Gruppen des Azure-Portals übereinstimmt.

Autorisieren des Server-API-/Web-API-Zugriffs

Eine SERVER-API-App kann Benutzer mit Autorisierungsrichtlinien für Sicherheitsgruppen, ME-ID-Administratorrollen und App-Rollen für den Zugriff auf sichere API-Endpunkte autorisieren, wenn ein Zugriffstoken groups-, wids- und role-Ansprüche enthält. Das folgende Beispiel erstellt eine Richtlinie für die ME-ID-Rolle Abrechnungsadministrator in der Program-Datei mithilfe der wids-Ansprüche (bekannte IDs oder Rollenvorlagen-IDs):

builder.Services.AddAuthorization(options =>
{
    options.AddPolicy("BillingAdministrator", policy => 
        policy.RequireClaim("wids", "b0f54661-2d74-4c50-afa3-1ec803f12efe"));
});

Die vollständige Liste der IDs für ME-ID-Administratorrollen finden Sie in der Azure-Dokumentation unter Rollenvorlagen-IDs. Weitere Informationen zu Autorisierungsrichtlinien finden Sie unter Richtlinienbasierte Autorisierung in ASP.NET Core.

Der Zugriff auf einen Controller in der SERVER-App kann auf der Verwendung eines [Authorize]-Attributs mit dem Namen der Richtlinie basieren (API-Dokumentation: AuthorizeAttribute).

Das folgende Beispiel beschränkt den Zugriff auf Abrechnungsdaten vom BillingDataController auf Azure-Abrechnungsadministratoren mit dem Richtliniennamen BillingAdministrator:

using Microsoft.AspNetCore.Authorization;
[Authorize(Policy = "BillingAdministrator")]
[ApiController]
[Route("[controller]")]
public class BillingDataController : ControllerBase
{
    ...
}

Weitere Informationen finden Sie unter Richtlinienbasierte Autorisierung in ASP.NET Core.

App-Rollen

Um die Anwendung im Azure-Portal so zu konfigurieren, dass sie Mitgliedschaftsansprüche von Anwendungsrollen bereitstellt, lesen Sie den Abschnitt Anwendungsrollen zu Ihrer Anwendung hinzufügen und im Token empfangen in der Entra-Dokumentation.

Im folgenden Beispiel wird angenommen, dass die CLIENT- und SERVER-Apps mit zwei Rollen konfiguriert und die Rollen einem Testbenutzer zugewiesen sind:

  • Admin
  • Developer

Hinweis

Wenn Sie eine gehostete Blazor WebAssembly-App oder ein Client-Server-Paar aus eigenständigen Apps (einer eigenständigen Blazor WebAssembly-App und einer ASP.NET Core-Server-API-/Web-API-App) entwickeln, muss die Manifesteigenschaft appRoles der Registrierungen des Clients und des Servers im Azure-Portal dieselben konfigurierten Rollen enthalten. Nachdem die Rollen im Manifest der Client-App festgelegt wurden, kopieren Sie diese in Gänze in das Manifest der Server-App. Wenn Sie das appRoles-Manifest zwischen den Client- und Server-App-Registrierungen nicht spiegeln, werden keine Rollenansprüche für authentifizierte Benutzende der Server-API/Web-API erstellt, auch wenn das Zugriffstoken über die richtigen Einträge in den Rollenansprüchen verfügt.

Zwar können Sie ohne Microsoft Entra ID-Premium-Konto nicht Rollen zu Gruppen zuweisen, aber Sie können Benutzenden Rollen zuweisen und Rollenansprüche für Benutzende mit einem Azure-Standardkonto erhalten. Für die Schritte in diesem Abschnitt ist kein ME-ID Premium-Konto erforderlich.

Befolgen Sie beim Arbeiten mit dem Standardverzeichnis die Anweisungen unter Anwendungsrollen zu Ihrer Anwendung hinzufügen und im Token empfangen, um Rollen zu konfigurieren und zuzuweisen. Wenn Sie nicht mit dem Standardverzeichnis arbeiten, bearbeiten Sie das Manifest der App im Azure-Portal, um die Rollen der App manuell im appRoles-Eintrag der Manifestdatei einzurichten. Im Folgenden sehen Sie einen appRoles-Beispieleintrag, der Admin- und Developer-Rollen erstellt. Diese Beispielrollen werden an späterer Stelle im Beispiel in diesem Abschnitt auf Komponentenebene verwendet, um Zugriffsbeschränkungen zu implementieren:

"appRoles": [
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Administrators manage developers.",
    "displayName": "Admin",
    "id": "{ADMIN GUID}",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Admin"
  },
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Developers write code.",
    "displayName": "Developer",
    "id": "{DEVELOPER GUID}",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Developer"
  }
],

Für die {ADMIN GUID} und {DEVELOPER GUID} Platzhalter im vorherigen Beispiel können Sie GUIDs mit einem Online-GUID-Generator (Google-Suchergebnis für "guid generator") generieren.

So weisen Sie einem Benutzer (oder einer Gruppe, wenn Sie über ein Azure-Konto im Premium-Tarif verfügen) eine Rolle zu:

  1. Navigieren Sie im ME-ID-Bereich des Azure-Portals zu Unternehmensanwendungen.
  2. Wählen Sie die App aus. Wählen Sie auf der Randleiste Verwalten>Benutzer und Gruppen aus.
  3. Aktivieren Sie das Kontrollkästchen für ein oder mehrere Benutzerkonten.
  4. Wählen Sie im Menü über der Liste der Benutzer die Option Zuweisung bearbeiten aus.
  5. Wählen Sie für den Eintrag Rolle auswählen die Option Keine ausgewählt aus.
  6. Klicken Sie in der Liste auf eine Rolle, und wählen Sie sie mit der Schaltfläche Auswählen aus.
  7. Verwenden Sie die Schaltfläche Zuweisen am unteren Bildschirmrand, um die Rolle zuzuweisen.

Mehrere Rollen werden im Azure-Portal durch separates Hinzufügen eines Benutzers für jede weitere Rollenzuweisung zugewiesen. Verwenden Sie die Schaltfläche Benutzer/Gruppe hinzufügen oben in der Liste der Benutzer, um einen Benutzer erneut hinzuzufügen. Führen Sie die obigen Schritte aus, um dem Benutzer eine weitere Rolle zuzuweisen. Sie können diesen Vorgang beliebig oft wiederholen, um einem Benutzer (oder einer Gruppe) zusätzliche Rollen hinzuzufügen.

Die im Abschnitt Benutzerdefiniertes Benutzerkonto gezeigte CustomAccountFactory ist so konfiguriert, dass sie auf einen role-Anspruch mit einem JSON-Arraywert reagiert. Fügen Sie die CustomAccountFactory in der CLIENT-App hinzu, und registrieren Sie sie, wie im Abschnitt Benutzerdefiniertes Benutzerkonto gezeigt. Für das Entfernen des ursprünglichen role-Anspruchs muss kein Code bereitgestellt werden, da das Framework diesen automatisch entfernt.

Geben Sie in der Program-Datei einer CLIENT-App den Anspruch namens appRole als Rollenanspruch für ClaimsPrincipal.IsInRole-Überprüfungen an:

builder.Services.AddMsalAuthentication(options =>
{
    ...

    options.UserOptions.RoleClaim = "appRole";
});

Hinweis

Wenn Sie lieber den directoryRoles-Anspruch (ADD-Administratorrollen) verwenden möchten, weisen Sie directoryRoles zu RemoteAuthenticationUserOptions.RoleClaim zu.

Geben Sie in der Program-Datei einer SERVER-App den Anspruch namens http://schemas.microsoft.com/ws/2008/06/identity/claims/role als Rollenanspruch für ClaimsPrincipal.IsInRole-Überprüfungen an:

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
    .AddMicrosoftIdentityWebApi(options =>
    {
        Configuration.Bind("AzureAd", options);
        options.TokenValidationParameters.RoleClaimType = 
            "http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
    },
    options => { Configuration.Bind("AzureAd", options); });

Hinweis

Wenn ein einzelnes Authentifizierungsschema registriert ist, wird es automatisch als Standardschema der App verwendet, und es ist nicht erforderlich, das Schema auf AddAuthentication oder über AuthenticationOptions anzugeben. Weitere Informationen finden Sie in der Übersicht über die ASP.NET Core- Authentifizierung und in der ASP.NET Core-Ankündigung (aspnet/Announcements #490).

Hinweis

Wenn Sie lieber den wids-Anspruch (ADD-Administratorrollen) verwenden möchten, weisen Sie wids zu TokenValidationParameters.RoleClaimType zu.

Nachdem Sie die vorherigen Schritte zum Erstellen und Zuweisen von Rollen für Benutzer (oder Gruppen, wenn Sie über ein Azure-Konto im Premium-Tarif verfügen) ausgeführt und die CustomAccountFactory mit dem Graph SDK wie weiter oben in diesem Artikel und unter Verwenden der Graph-API mit der Blazor WebAssembly von ASP.NET Core beschrieben implementiert haben, sollte ein appRole-Anspruch für jede Rolle, die einem angemeldeten Benutzer zugewiesen ist (oder Rollen, die Gruppen zugewiesen sind, denen er angehört), angezeigt werden. Führen Sie die App mit einem Testbenutzer aus, um sicherzustellen, dass die Ansprüche wie erwartet vorhanden sind. Beim lokalem Testen mit dem Graph SDK empfehlen wir die Verwendung einer neuen privaten bzw. Inkognito-Browsersitzung für jeden Test, um zu verhindern, dass Tests durch vorhandene Cookies beeinträchtigt werden. Weitere Informationen finden Sie unter Sichern einer eigenständigen ASP.NET Core-Blazor WebAssembly-App mit Microsoft Entra ID.

Die Komponentenautorisierungsansätze sind Stand jetzt funktional. Jeder der Autorisierungsmechanismen in Komponenten der CLIENT-App kann die Rolle Admin verwenden, um Benutzer zu autorisieren:

Mehrere Rollentests werden unterstützt:

  • Legen Sie mithilfe der AuthorizeView-Komponente als erforderlich fest, dass der Benutzer entweder die Rolle Admin oder die Rolle Developer innehat:

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • Legen Sie mithilfe der AuthorizeView-Komponente als erforderlich fest, dass der Benutzer sowohl die Rolle Admin als auch die Rolle Developer innehat:

    <AuthorizeView Roles="Admin">
        <AuthorizeView Roles="Developer" Context="innerContext">
            ...
        </AuthorizeView>
    </AuthorizeView>
    

    Weitere Informationen zu Context für die innere AuthorizeView finden Sie unter ASP.NET Core-Blazor-Authentifizierung und -Autorisierung.

  • Legen Sie mithilfe des [Authorize]-Attributs als erforderlich fest, dass der Benutzer entweder die Rolle Admin oder die Rolle Developer innehat:

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • Legen Sie mithilfe des [Authorize]-Attributs als erforderlich fest, dass der Benutzer sowohl die Rolle Admin als auch die Rolle Developer innehat:

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • Legen Sie per prozeduralem Code als erforderlich fest, dass der Benutzer entweder die Rolle Admin oder die Rolle Developer innehat:

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • Legen Sie per prozeduralem Code als erforderlich fest, dass der Benutzer sowohl die Rolle Admin als auch die Rolle Developer innehat. Ändern Sie dazu im vorherigen Beispiel das bedingte OR (||) in ein bedingtes AND (&&):

    if (user.IsInRole("Admin") && user.IsInRole("Developer"))
    

Jeder der Autorisierungsmechanismen in Controllern der SERVER-App kann die Rolle Admin verwenden, um Benutzer zu autorisieren:

Mehrere Rollentests werden unterstützt:

  • Legen Sie mithilfe des [Authorize]-Attributs als erforderlich fest, dass der Benutzer entweder die Rolle Admin oder die Rolle Developer innehat:

    [Authorize(Roles = "Admin, Developer")]
    
  • Legen Sie mithilfe des [Authorize]-Attributs als erforderlich fest, dass der Benutzer sowohl die Rolle Admin als auch die Rolle Developer innehat:

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • Legen Sie per prozeduralem Code als erforderlich fest, dass der Benutzer entweder die Rolle Admin oder die Rolle Developer innehat:

    static readonly string[] scopeRequiredByApi = new string[] { "API.Access" };
    
    ...
    
    [HttpGet]
    public IEnumerable<ReturnType> Get()
    {
        HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
    
        if (User.IsInRole("Admin") || User.IsInRole("Developer"))
        {
            ...
        }
        else
        {
            ...
        }
    
        return ...
    }
    
  • Legen Sie per prozeduralem Code als erforderlich fest, dass der Benutzer sowohl die Rolle Admin als auch die Rolle Developer innehat. Ändern Sie dazu im vorherigen Beispiel das bedingte OR (||) in ein bedingtes AND (&&):

    if (User.IsInRole("Admin") && User.IsInRole("Developer"))
    

Da bei Zeichenfolgenvergleichen in .NET zwischen Groß- und Kleinschreibung unterschieden wird, wird auch beim Abgleich von Rollennamen zwischen Groß- und Kleinschreibung unterschieden. Beispielsweise wird Admin (mit Großbuchstabe A) nicht als dieselbe Rolle wie admin (mit Kleinbuchstabe a) behandelt.

Die Pascal-Schreibweise wird in der Regel für Rollennamen (z. B. BillingAdministrator) verwendet, aber die Verwendung der Pascal-Schreibweise ist keine strenge Anforderung. Unterschiedliche Groß-/Kleinschreibungen wie Camel Case, Kebab Case und Snake Case sind zulässig. Die Verwendung von Leerzeichen in Rollennamen ist ebenfalls ungewöhnlich, aber zulässig. Beispielsweise ist billing administrator ein ungewöhnliches Rollennamenformat in .NET-Apps, aber gültig.

Zusätzliche Ressourcen