Microsoft Entra (ME-ID) グループ、管理者ロール、およびアプリ ロール

Note

これは、この記事の最新バージョンではありません。 現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

重要

この情報はリリース前の製品に関する事項であり、正式版がリリースされるまでに大幅に変更される可能性があります。 Microsoft はここに示されている情報について、明示か黙示かを問わず、一切保証しません。

現在のリリースについては、この記事の .NET 8 バージョンを参照してください。

この記事では、Microsoft Entra ID のグループとロールを使用するように Blazor WebAssembly を構成する方法を説明します。

Microsoft Entra (ME-ID) には、ASP.NET Core Identity と組み合わせることができる承認方法がいくつか用意されています。

  • グループ
    • セキュリティ
    • Microsoft 365
    • 配布
  • 役割
    • ME-ID 管理者ロール
    • アプリ ロール

この記事のガイダンスは、次のトピックで説明されている Blazor WebAssembly ME-ID デプロイ シナリオに適用されます。

この記事のガイダンスでは、クライアントとサーバーのアプリについて説明します。

  • クライアント: スタンドアロン Blazor WebAssembly アプリ。
  • サーバー: ASP.NET Core サーバー API/Web API アプリ。 スタンドアロン Blazor WebAssembly アプリについては、記事全体を通してサーバーのガイダンスを無視できます。
  • クライアント: スタンドアロン Blazor WebAssembly アプリ、またはホストされた BlazorソリューションClient アプリ。
  • サーバー: ASP.NET Core サーバー API または Web API アプリ、またはホストされた Blazor ソリューションの Server アプリ。 スタンドアロン Blazor WebAssembly アプリについては、記事全体を通してサーバーのガイダンスを無視できます。

この記事の例では、新しい .NET/C# の機能を利用します。 この例に .NET 7 以前を使用する場合は、若干の変更が必要です。 ただし、ME-ID と Microsoft Graph の操作に関連するテキストとコードの例は、ASP.NET Core のすべてのバージョンで同じです。

前提条件

この記事のガイダンスでは、「ASP.NET Core Blazor WebAssembly で Graph API を使用する」の Graph SDK のガイダンスに従って Microsoft Graph API を実装します。 Graph SDK の実装ガイダンスに従ってアプリを構成し、アプリがテスト ユーザー アカウントの Graph API データを取得できることをテストして確認します。 さらに、Graph API 記事のセキュリティに関する記事のクロスリンクを参照して、Microsoft Graph のセキュリティの概念を確認してください。

Graph SDK をローカル環境でテストする場合は、残っている cookie がテストに干渉しないよう、テストのたびに新しいプライベートまたはシークレット ブラウザー セッションを使うことをお勧めします。 詳しくは、「Microsoft Entra ID を使用して、ASP.NET Core Blazor WebAssembly スタンドアロン アプリをセキュリティで保護する」をご覧ください。

スコープ

Microsoft Graph API によるユーザー プロファイル、ロールの割り当て、グループ メンバーシップ データの呼び出しを許可するには:

  • クライアント アプリは、Azure portal で "委任された" User.Read スコープ (https://graph.microsoft.com/User.Read) を使用して構成されます。これは、ユーザー データの読み取りアクセス権は個々のユーザーに付与 (委任) されたスコープによって決まるためです。
  • サーバー アプリは、Azure portal で "アプリケーション" GroupMember.Read.All スコープ (https://graph.microsoft.com/GroupMember.Read.All) を使用して構成されます。これは、アクセスはアプリがグループ メンバーシップに関する情報を取得するために行われ、グループ メンバーに関するデータにアクセスするための個々のユーザー承認に基づかないことが理由です。

上記のスコープが、前述のトピックで説明した ME-ID のデプロイ シナリオで必要なスコープ ("Microsoft アカウントによるスタンドアロン" または "ME-ID によるスタンドアロン") に加えて必要です。

上記のスコープが、前述のトピックで説明した ME-ID のデプロイ シナリオで必要なスコープ (「Microsoft アカウントによるスタンドアロン」、「ME-ID によるスタンドアロン」、「ME-ID によるホスティング」) に加えて必要です。

詳細については、「Microsoft ID プラットフォームでのアクセス許可と同意の概要」および「Microsoft Graph のアクセス許可の概要」を参照してください。

Note

"アクセス許可" と "スコープ" という語は、Azure portal や、Microsoft および外部のさまざまなドキュメントのセットで同じように使用されています。 この記事では、Azure portal でアプリに割り当てられたアクセス許可に対して、"スコープ" という語を使用します。

グループ メンバーシップ要求の属性

クライアントおよびサーバー アプリに対する Azure portal のアプリ マニフェストで、groupMembershipClaims 属性All に設定します。 All の値を設定すると、ME-ID が既知の ID 要求 (wids) のサインインしているユーザーのセキュリティ グループ、配布グループ、ロールのすべてを送信します。

  1. アプリの Azure portal の登録を開きます。
  2. サイド バーで [管理]>[マニフェスト] を選択します。
  3. groupMembershipClaims 属性を見つけます。
  4. 値を All に設定します ("groupMembershipClaims": "All")。
  5. 変更を加えた場合は、[保存] ボタンを選択します。

カスタム ユーザー アカウント

Azure portal で ME-ID セキュリティ グループと ME-ID 管理者ロールにユーザーを割り当てます。

この記事の例では:

  • サーバー API データへのアクセスを認可するために、ユーザーが Azure portal ME-ID テナントの ME-ID 課金管理者ロールに割り当てられているとします。
  • 認可ポリシーを使用して、クライアントおよびサーバー アプリ内でアクセスを制御します。

クライアント アプリで、RemoteUserAccount を拡張して次のプロパティを含めます。

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; }
}

パッケージ参照を Microsoft.GraphCLIENT アプリに追加します。

Note

.NET アプリへのパッケージの追加に関するガイダンスについては、「パッケージ利用のワークフロー」 (NuGet ドキュメント) の "パッケージのインストールと管理" に関する記事を参照してください。 NuGet.org で正しいパッケージ バージョンを確認します。

記事「ASP.NET Core Blazor WebAssembly で Graph API を使用する」の Graph SDK のガイダンスにある Graph SDK ユーティリティ クラスと構成を追加します。 記事のサンプル wwwroot/appsettings.json ファイルで示されているように、アクセス トークンの User.Read スコープを指定します。

次のカスタム ユーザー アカウント ファクトリをクライアント アプリに追加します。 カスタム ユーザー ファクトリは、以下を確立するために使用されます。

  • アプリ ロールの要求 (appRole) (「アプリ ロール」セクションで説明します)。
  • ME-ID 管理者ロールの要求 (directoryRole)。
  • ユーザーの携帯電話番号 (mobilePhone) と勤務先所在地 (officeLocation) に対するユーザー プロファイル データ要求の例。
  • ME-ID グループ要求 (directoryGroup)。
  • ILogger (logger) (情報やエラーをログする必要がある場合に便利なように)。

CustomAccountFactory.cs:

次の例では、プロジェクトのアプリ設定ファイルにベース URL のエントリが含まれていることを前提としています。

{
  "MicrosoftGraph": {
    "BaseUrl": "https://graph.microsoft.com/{VERSION}",
    ...
  }
}

前の例で、{VERSION} プレースホルダーは MS Graph API のバージョンです (例: v1.0)。

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(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger,
        IConfiguration config)
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;
    private readonly string? baseUrl = 
        config.GetSection("MicrosoftGraph")["BaseUrl"];

    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 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;
    }
}
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(IAccessTokenProviderAccessor accessor,
        IServiceProvider serviceProvider,
        ILogger<CustomAccountFactory> logger)
    : AccountClaimsPrincipalFactory<CustomUserAccount>(accessor)
{
    private readonly ILogger<CustomAccountFactory> logger = logger;
    private readonly IServiceProvider serviceProvider = serviceProvider;

    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;
    }
}

上記のコードには、推移的なメンバーシップは含まれていません。 アプリで直接的および推移的なグループ メンバーシップの要求が必要である場合は、MemberOf プロパティ (IUserMemberOfCollectionWithReferencesRequestBuilder) を TransitiveMemberOf (IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder) に置き換えます。

上記のコードでは、ME-ID 管理者ロール (#microsoft.graph.directoryRole の種類) であるグループ メンバーシップの要求 (groups) が無視されます。これは、Microsoft ID プラットフォームによって返される GUID 値が、ロール テンプレート ID ではなく ME-ID 管理者ロールのエンティティ ID であるためです。 エンティティ ID は Microsoft ID プラットフォームのテナント間で一定ではないため、アプリでユーザーの認可ポリシーを作成するために使用しないでください。 wids 要求によって提供される ME-ID 管理者ロールのロール テンプレート ID を常に使用してください。

クライアント アプリで、カスタム ユーザー アカウント ファクトリを使用するように MSAL 認証を構成します。

Program ファイルで Microsoft.AspNetCore.Components.WebAssembly.Authentication 名前空間が使われていることを確認します。

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

AddMsalAuthentication 呼び出しを次のように更新します。 Blazor フレームワークの RemoteUserAccount は、MSAL 認証とアカウント要求プリンシパル ファクトリに対してアプリの CustomUserAccount に置き換えられていることに注意してください。

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

ASP.NET Core Blazor WebAssembly で Graph API を使用する」の記事で説明されている Graph SDK コードが存在し、wwwroot/appsettings.json の構成が Graph SDK のガイダンスに従って正しいことを確認します。

var baseUrl = string.Join("/", 
    builder.Configuration.GetSection("MicrosoftGraph")["BaseUrl"], 
    builder.Configuration.GetSection("MicrosoftGraph")["Version"]);
var scopes = builder.Configuration.GetSection("MicrosoftGraph:Scopes")
    .Get<List<string>>();

builder.Services.AddGraphClient(baseUrl, scopes);

wwwroot/appsettings.json:

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

承認の構成

クライアント アプリの Program ファイルで、各アプリ ロール、ME-ID 管理者ロール、またはセキュリティ グループに対してポリシーを作成します。 次の例では、ME-ID 課金管理者ロールに対するポリシーを作成します。

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

ME-ID 管理者の役割 ID に関する完全な一覧については、Entra ドキュメントの「ロール テンプレート ID」を参照してください。 承認ポリシーの詳細については、「ASP.NET Core でのポリシー ベースの認可」を参照してください。

次の例では、クライアント アプリで前述のポリシーを使用してユーザーを承認します。

AuthorizeView コンポーネントではポリシーが使用されます。

<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>

コンポーネント全体へのアクセスは、[Authorize] 属性ディレクティブ (AuthorizeAttribute) を使用するポリシーを基にして行うことができます。

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

ユーザーが承認されていない場合は、ME-ID サインイン ページにリダイレクトされます。

ポリシー チェックは、手続き型ロジックを使用してコードで実行することもできます。

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.";
        }
    }
}

サーバー API または Web API のアクセスを承認する

サーバー API アプリでは、アクセス トークンに groupswidsrole の要求が含まれている場合に、セキュリティ グループ、ME-ID 管理者ロール、およびアプリ ロールに対する認可ポリシーを使用して、セキュリティで保護された API エンドポイントにアクセスすることをユーザーに許可できます。 次の例では、Program ファイルで wids (既知の ID またはロール テンプレート ID) 要求を使用して、ME-ID 課金管理者ロールに対するポリシーを作成しています。

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

ME-ID 管理者ロールの ID の完全な一覧については、Azure ドキュメントの「ロール テンプレート ID」を参照してください。 承認ポリシーの詳細については、「ASP.NET Core でのポリシー ベースの認可」を参照してください。

サーバー アプリのコントローラーへのアクセスは、[Authorize] 属性とポリシー名の使用に基づいて行うことができます (API ドキュメント:AuthorizeAttribute)。

次の例では、BillingDataController からの課金データへのアクセスを、BillingAdministrator というポリシー名を持つ Azure 課金管理者に制限しています。

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

詳細については、「ASP.NET Core でのポリシー ベースの認可」を参照してください。

アプリ ロール

Azure portal で、アプリをアプリ ロールメンバーシップ要求を提供するように構成するには、Entra ドキュメントの、「アプリケーションにアプリ ロールを追加し、それらをトークン で受け取る」を参照してください。

以下の例では、クライアントサーバー アプリが 2 つのロールを使用して構成されていること、およびロールがテスト ユーザーに割り当てられていることを前提としています。

  • Admin
  • Developer

Note

スタンドアロン アプリ (スタンドアロンの Blazor WebAssembly アプリおよび ASP.NET Core サーバー API または Web API アプリ) のクライアントとサーバーのペアを開発する場合、クライアントとサーバー両方の Azure portal アプリ登録の appRoles マニフェスト プロパティには、同じ構成されたロールを含める必要があります。 クライアント アプリのマニフェストでロールを確立したら、それら全体をサーバー アプリのマニフェストにコピーします。 クライアントとサーバーのアプリ登録の間でマニフェスト appRoles をミラー化しないと、サーバー API または Web API の認証済みユーザーに対して、そのアクセス トークンに role 要求で適切なエントリがあっても、ロール要求が確立されません。

Note

ホストされている Blazor WebAssembly アプリ、またはスタンドアロン アプリ (スタンドアロンの Blazor WebAssembly アプリおよび ASP.NET Core サーバー API または Web API アプリ) のクライアントとサーバーのペアを開発する場合、クライアントとサーバー両方の Azure portal アプリ登録の appRoles マニフェスト プロパティには、同じ構成されたロールを含める必要があります。 クライアント アプリのマニフェストでロールを確立したら、それら全体をサーバー アプリのマニフェストにコピーします。 クライアントとサーバーのアプリ登録の間でマニフェスト appRoles をミラー化しないと、サーバー API または Web API の認証済みユーザーに対して、そのアクセス トークンに role 要求で適切なエントリがあっても、ロール要求が確立されません。

Microsoft Entra ID Premium アカウントがないとグループにロールを割り当てることはできませんが、Standard Azure アカウントを使用して、ユーザーにロールを割り当て、ユーザーに対する role 要求を受け取ることができます。 このセクションのガイダンスでは、ME-ID Premium アカウントは必要ありません。

Premium レベルの Azure アカウントをお持ちの場合は、Azure portal のアプリ登録のサイド バーに [管理]>[アプリのロール] が表示されます。 「アプリケーションにアプリ ロールを追加し、それらをトークンで受け取る」のガイダンスに従って、アプリのロールを構成します。

Premium レベルの Azure アカウントがない場合は、Azure portal でアプリのマニフェストを編集します。 「アプリケーション ロール: 実装」のガイダンスに従って、マニフェスト ファイルの appRoles エントリでアプリのロールを手動で確立します。 変更をファイルに保存します。

Admin ロールと Developer ロールを作成する appRoles エントリの例を次に示します。 これらのロールの例は、このセクションの例の後半でコンポーネント レベルでアクセス制限を実装するために使用されます。

"appRoles": [
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Administrators manage developers.",
    "displayName": "Admin",
    "id": "584e483a-7101-404b-9bb1-83bf9463e335",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Admin"
  },
  {
    "allowedMemberTypes": [
      "User"
    ],
    "description": "Developers write code.",
    "displayName": "Developer",
    "id": "82770d35-2a93-4182-b3f5-3d7bfe9dfe46",
    "isEnabled": true,
    "lang": null,
    "origin": "Application",
    "value": "Developer"
  }
],

ユーザー (または Premium レベルの Azure アカウントがある場合はグループ) にロールを割り当てるには:

  1. Azure portal の ME-ID 領域で [エンタープライズ アプリケーション] に移動します。
  2. アプリを選びます。 サイド バーから [管理]>[ユーザーとグループ] を選択します。
  3. 1 つ以上のユーザー アカウントのチェックボックスをオンにします。
  4. ユーザーの一覧の上にあるメニューから、[割り当ての編集] を選択します。
  5. [ロールを選択する] エントリに対して、[選択されていません] を選択します。
  6. 一覧からロールを選択し、[選択] ボタンを使用して選択します。
  7. 画面の下部にある [割り当て] ボタンを使用して、ロールを割り当てます。

Azure portal で各追加ロール割り当てに対して ユーザーを再追加する ことにより、複数のロールを割り当てます。 ユーザーの一覧の上部にある [ユーザーまたはグループの追加] ボタンを使用して、ユーザーを再追加します。 前の手順を使用して、ユーザーに別のロールを割り当てます。 このプロセスを必要な回数だけ繰り返して、ユーザー (またはグループ) にロールを追加できます。

カスタム ユーザー アカウント」セクションで示されている CustomAccountFactory は、JSON 配列値を持つ role 要求に対して動作するように設定されています。 「カスタム ユーザー アカウント」セクションで示されているように、クライアント アプリに CustomAccountFactory を追加して登録します。 元の role 要求はフレームワークによって自動的に削除されるため、それを削除するためのコードを提供する必要はありません。

クライアント アプリの Program ファイルで、ClaimsPrincipal.IsInRole のチェック用にロール要求として "appRole" という名前の要求を指定します。

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

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

Note

directoryRoles 要求 (管理者ロールの追加) を使用したい場合は、"directoryRoles" を RemoteAuthenticationUserOptions.RoleClaim に代入します。

サーバー アプリの Program ファイルで、ClaimsPrincipal.IsInRole のチェック用にロール要求として "http://schemas.microsoft.com/ws/2008/06/identity/claims/role" という名前の要求を指定します。

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); });

Note

1 つの認証スキームが登録されると、認証スキームがアプリの既定のスキームとして自動的に使用され、スキームを AddAuthentication に指定、または AuthenticationOptions 経由にする必要はありません。 詳細については、「ASP.NET Core の認証の概要」と ASP.NET Core のお知らせ (aspnet/Announcements #490) を参照してください。

Note

wids 要求 (管理者ロールの追加) を使用したい場合は、"wids" を TokenValidationParameters.RoleClaimType に代入します。

前の手順を完了してロールを作成し、ユーザー (または、Premium レベルの Azure アカウントを持っている場合はグループ) に割り当て、前述のこの記事と「ASP.NET Core Blazor WebAssembly で Graph API を使用する」で説明されているように Graph SDK で CustomAccountFactory を実装したら、サインインしているユーザーが割り当てられている各割り当て済みロール (またはユーザーが所属しているグループに割り当てられているロール) の appRole 要求が表示されます。 テスト ユーザーを使ってアプリを実行し、要求が期待どおりに存在することを確認します。 Graph SDK をローカル環境でテストする場合は、残っている cookie がテストに干渉しないよう、テストのたびに新しいプライベートまたはシークレット ブラウザー セッションを使うことをお勧めします。 詳しくは、「Microsoft Entra ID を使用して、ASP.NET Core Blazor WebAssembly スタンドアロン アプリをセキュリティで保護する」をご覧ください。

この時点でコンポーネントの承認方法が機能しています。 クライアント アプリのコンポーネント内のすべての認可メカニズムで、Admin ロールを使用してユーザーを承認できます。

複数のロール テストがサポートされています。

  • AuthorizeView コンポーネントを使用して、ユーザーが AdminまたはDeveloper ロールのいずれかであることを要求します。

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • AuthorizeView コンポーネントを使用して、ユーザーが AdminおよびDeveloper ロールの両方であることを要求します。

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

    内部 AuthorizeViewContext に関する詳細情報については、「ASP.NET Core Blazor 認証および許可」を参照してください。

  • [Authorize] 属性を使用して、ユーザーが AdminまたはDeveloper ロールのいずれかであることを要求します。

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • [Authorize] 属性を使用して、ユーザーが AdminおよびDeveloper ロールの両方であることを要求します。

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • 手続き型のコードを使用して、ユーザーが AdminまたはDeveloper ロールのいずれかであることを要求します。

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • 手続き型のコードを使用して、ユーザーが AdminおよびDeveloper ロールの両方であることを要求します。それには、前の例の条件付き OR (||)条件付き AND (&&) に変更します。

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

サーバー アプリのコントローラー内のすべての認可メカニズムで、Admin ロールを使用してユーザーを承認できます。

複数のロール テストがサポートされています。

  • [Authorize] 属性を使用して、ユーザーが AdminまたはDeveloper ロールのいずれかであることを要求します。

    [Authorize(Roles = "Admin, Developer")]
    
  • [Authorize] 属性を使用して、ユーザーが AdminおよびDeveloper ロールの両方であることを要求します。

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • 手続き型のコードを使用して、ユーザーが AdminまたはDeveloper ロールのいずれかであることを要求します。

    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 ...
    }
    
  • 手続き型のコードを使用して、ユーザーが AdminおよびDeveloper ロールの両方であることを要求します。それには、前の例の条件付き OR (||)条件付き AND (&&) に変更します。

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

.NET 文字列の比較は既定では大文字と小文字が区別されるため、ロール名の照合でも大文字と小文字が区別されます。 たとえば、Admin (大文字 A) は、admin (小文字 a) と同じロールとして扱われません。

通常、パスカル ケースはロール名に使用されますが (例: BillingAdministrator)、パスカル ケースの使用は厳密な要件ではありません。 キャメル ケース、ケバブ ケース、スネーク ケースなど、さまざまなケース スキームが許可されています。 ロール名でのスペースの使用も通常とは異なりますが、許可されています。 たとえば、billing administrator は .NET アプリでは通常とは異なるロール名の形式ですが、有効です。

その他のリソース