共用方式為


Microsoft Entra (ME-ID) 群組、管理員角色和應用程式角色(.NET 5 至 .NET 7)

注意

這不是這篇文章的最新版本。 如需目前的 ASP.NET Core 版本,請參閱具有 Microsoft Entra ID 群組和角色的 ASP.NET Core Blazor WebAssembly 最新版本。

本文說明如何將 Blazor WebAssembly 設定為使用 Microsoft Entra ID 群組和角色。

Microsoft Entra (ME-ID) 提供數種可與 ASP.NET Core Identity 結合的授權方法:

  • 群組
    • 安全性
    • Microsoft 365
    • 散發
  • 角色
    • ME-ID 管理員角色
    • 應用程式角色

本文中的指引適用於下列文章中所述的 Blazor WebAssembly ME-ID 部署案例:

本文的指引提供用戶端和伺服器應用程式的指示:

  • 用戶端:獨立 Blazor WebAssembly 應用程式或託管 Blazor解決方案Client應用程式。
  • 伺服器:ASP.NET Core 伺服器 API/Web API 應用程式或託管 Blazor 解決方案的Server應用程式。 對於獨立 Blazor WebAssembly 應用程式,您可以忽略整篇文章中的伺服器指引。

本文中的範例會利用新的 .NET/C# 功能。 在.NET 7 或更早版本中使用這些範例時,需要略為修改。 不過,對於所有 ASP.NET Core 版本,與 ME-ID 和 Microsoft Graph 互動相關的文字和程式碼範例都相同。

必要條件

本文中的指引會根據 使用圖形 API 搭配 ASP.NET Core 中的 Blazor WebAssembly Graph SDK 指引,實作 Microsoft Graph API。 請遵循 Graph SDK 實作指引來設定應用程式並進行測試,以確認應用程式可以取得測試使用者帳戶的圖形 API 資料。 此外,請參閱 Graph API 文章的安全性文章交叉連結,以檢閱 Microsoft Graph 安全性概念。

在本機使用 Graph SDK 進行測試時,我們建議針對每個測試使用新的私人/incognito 瀏覽器工作模式,以防止徘徊的 cookie 干擾測試。 如需詳細資訊,請參閱使用 Microsoft Entra ID 保護 ASP.NET Core Blazor WebAssembly 獨立應用程式

範圍

若要允許 Microsoft Graph API 要求使用者設定檔、角色指派和群組成員資格資料:

  • 用戶端應用程式會在 Azure 入口網站中設定為委派的User.Read 範圍 (https://graph.microsoft.com/User.Read),因為讀取使用者資料的存取權是取決於授與給個別使用者的範圍。
  • 伺服器應用程式是在 Azure 入口網站中設定應用程式 GroupMember.Read.All 範圍 (https://graph.microsoft.com/GroupMember.Read.All),因為存取權是讓應用程式取得群組成員資格的相關資訊,而不是根據個別使用者授權來存取群組成員的相關資料。

除了先前所列文章(「使用 Microsoft 帳戶獨立」「使用 ME-ID 獨立」「使用 ME-ID 託管」)描述的 ME-ID 部署案例中所需的範圍之外,還需要上述範圍。

如需詳細資訊,請參閱 Microsoft identity 平台的權限和同意概觀 以及 Microsoft Graph 權限概觀

權限範圍代表相同的事項,在安全性文件和 Azure 入口網站中交換使用。 除非文字指代 Azure 入口網站,否則本文會在指代 Graph 權限時使用範圍/範圍

範圍不區分大小寫,因此 User.Readuser.read 相同。 請隨意使用任一格式,但建議在應用程式碼之間選擇一致的格式。

群組成員資格宣告屬性

在 Azure 入口網站中用戶端伺服器應用程式的應用程式資訊清單中,將 groupMembershipClaims 屬性 設定為 DirectoryRole。 值 DirectoryRole 會導致 ME-ID 在已知識別碼宣告 (wids) 中傳送所有已登入使用者的角色:

  1. 開啟應用程式的 Azure 入口網站註冊。
  2. 選取資訊看板中的 [管理]>[資訊清單]
  3. 尋找 groupMembershipClaims 屬性。
  4. 將值設定為 DirectoryRole ("groupMembershipClaims": "DirectoryRole")。
  5. 如果您做了變更,請選取 [儲存] 按鈕。

在 Azure 入口網站中用戶端伺服器應用程式的應用程式資訊清單中,將 groupMembershipClaims 屬性 設定為 All。 值 All 會導致 ME-ID 在已知識別碼宣告 (wids) 中傳送所有安全性群組、通訊群組,以及已登入使用者的角色:

  1. 開啟應用程式的 Azure 入口網站註冊。
  2. 選取資訊看板中的 [管理]>[資訊清單]
  3. 尋找 groupMembershipClaims 屬性。
  4. 將值設定為 All ("groupMembershipClaims": "All")。
  5. 如果您做了變更,請選取 [儲存] 按鈕。

自訂使用者帳戶

在 Azure 入口網站中,將使用者指派給 ME-ID 安全性群組和 ME-ID 管理員角色。

本文中的範例:

  • 假設使用者已指派給 Azure 入口網站 ME-ID 租用戶中的 ME-ID「計費管理員」角色,以取得存取伺服器 API 資料的授權。
  • 使用授權原則來控制用戶端伺服器應用程式內的存取。

用戶端應用程式中,擴充 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.Graph用戶端應用程式。

注意

如需將套件新增至 .NET 應用程式的指引,請參閱在套件取用工作流程 (NuGet 文件)安裝及管理套件底下的文章。 在 NuGet.org 確認正確的套件版本。

使用圖形 API 搭配 ASP.NET Core Blazor WebAssembly 一文的 Graph SDK 指引新增 Graph SDK 公用程式類別和設定。 指定存取權杖的 User.Read 範圍,如本文在其範例 wwwroot/appsettings.json 檔案中所示。

將下列自訂使用者帳戶處理站新增至用戶端應用程式。 自訂使用者處理站用來建立:

  • 應用程式角色宣告 (appRole) (涵蓋在應用程式角色一節中)。
  • ME-ID 管理員角色宣告 (directoryRole)。
  • 使用者行動電話號碼 (mobilePhone) 和辦公室位置 (officeLocation) 的範例使用者設定檔資料宣告。
  • ME-ID 群組宣告 (directoryGroup)。
  • ILogger (logger),方便您使用,如果您想要記錄資訊或錯誤的話。

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

上述程式碼不會包含可轉移的成員資格。 如果應用程式需要直接和可轉移的群組成員資格宣告,請將 MemberOf 屬性 (IUserMemberOfCollectionWithReferencesRequestBuilder) 取代 TransitiveMemberOf (IUserTransitiveMemberOfCollectionWithReferencesRequestBuilder)。

上述程式碼會忽略本身為 ME-ID 管理員角色 (#microsoft.graph.directoryRole 類型) 的群組成員資格宣告 (groups),因為 ME-ID 所傳回的 GUID 值是管理員角色實體識別碼,而不是角色範本識別碼。 實體識別碼在租用戶之間並不穩定,因此不應該用來針對應用程式中的使用者建立授權原則。 針對 wids 宣告所提供的 ME-ID 管理員角色,一律使用範本識別碼

值為 b79fbf4d-3ef9-4689-8143-76b194e85509wids 宣告(也因此 directoryRole 宣告)存在於租用戶的非來賓帳戶。 其不會參考 ME-ID 管理員角色範本識別碼。

用戶端應用程式中,將 MSAL 驗證設定為使用自訂使用者帳戶處理站。

確認 Program 檔案使用的是 Microsoft.AspNetCore.Components.WebAssembly.Authentication 命名空間:

using Microsoft.AspNetCore.Components.WebAssembly.Authentication;

更新 AddMsalAuthentication 對下列項目的呼叫。 請注意,對於 MSAL 驗證和帳戶宣告主體處理站,Blazor 架構的 RemoteUserAccount 會被應用程式的 CustomUserAccount 所取代:

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

確認使用圖形 API 搭配 ASP.NET Core Blazor WebAssembly 一文所述的 Graph SDK 程式碼存在,且根據 Graph SDK 指引,wwwroot/appsettings.json 設定是正確的:

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"
    ]
  }
}

授權設定

用戶端應用程式中,為 Program 檔案中的每個應用程式角色、ME-ID 管理員角色或安全性群組建立原則。 下列範例會建立 ME-ID 內建「計費管理員」角色的原則:

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

如需 ME-ID 管理員角色識別碼的完整清單,請參閱 Entra 文件中的角色範本識別碼。 如需授權原則的詳細資訊,請參閱 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.";
        }
    }
}

使用上述方法,您也可以為應用程式角色建立原則型存取,其中的 GUID 用於在 Azure 入口網站應用程式資訊清單的 appRoles 元素中設定的原則,以及建立安全性群組,其中的 GUID 所用於的原則需符合 Azure 入口網站 [群組] 窗格中的群組 [物件識別碼]

授權伺服器 API/Web API 存取

當存取權杖包含 groupswidsrole 宣告時,伺服器 API 應用程式可以使用安全性群組、ME-ID 管理員角色和應用程式角色的授權原則,授權使用者存取安全的 API 端點。 下列範例會使用 wids (已知識別碼/角色範本識別碼) 宣告,為 Program 檔案中的 ME-ID「計費管理員」角色建立原則:

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

如需 ME-ID 管理員角色識別碼的完整清單,請參閱 Azure 文件中的角色範本識別碼。 如需授權原則的詳細資訊,請參閱 ASP.NET Core 中的原則型授權

存取伺服器應用程式中的控制器,可以基於使用 [Authorize] 屬性搭配原則名稱 (API 文件:AuthorizeAttribute) 來進行。

下列範例會限制存取從 BillingDataController 至 Azure 計費管理員 (原則名稱為 BillingAdministrator) 的計費資料:

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

如需詳細資訊,請參閱 ASP.NET Core 中的原則型授權

應用程式角色

若要在 Azure 入口網站中設定應用程式,以提供應用程式角色成員資格宣告,請參閱 Entra 文件中的將應用程式角色新增至應用程式,並在權杖中接收這些角色

下列範例假設用戶端伺服器應用程式使用兩個角色進行設定,並將這些角色指派給測試使用者:

  • Admin
  • Developer

注意

開發託管 Blazor WebAssembly 應用程式或獨立應用程式的用戶端-伺服器配對 (獨立 Blazor WebAssembly 應用程式和 ASP.NET Core 伺服器 API/Web API 應用程式) 時,用戶端和伺服器 Azure 入口網站應用程式註冊的 appRoles 資訊清單屬性必須包含相同的設定角色。 在用戶端應用程式的資訊清單中建立角色之後,請將其完整地複製到伺服器應用程式的資訊清單。 如果您未在用戶端與伺服器應用程式註冊之間鏡像資訊清單 appRoles,則不會為伺服器 API/Web API 已驗證使用者建立角色宣告,即使其存取權杖在角色宣告中具有正確的條目也一樣。

雖然若沒有 Microsoft Entra ID 進階帳戶,您無法 將角色指派給群組 ,但您可以將角色指派給使用者,並使用標準 Azure 帳戶接收使用者的角色宣告。 本節中的指引不需要 ME-ID 進階帳戶。

使用預設目錄時,請依照指導 將應用程式角色新增至應用程式,在權杖中接收這些角色 ,並設定指派應用程式的角色。 如果您未使用預設目錄,請在 Azure 入口網站 中編輯應用程式的資訊清單,以在資訊清單檔的 appRoles 輸入中,手動建立應用程式的角色。 以下是建立 AdminDeveloper 角色的範例 appRoles 項目。 這些範例角色稍後會用於本節元件層級的範例中,以實作存取限制:

"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"
  }
],

{ADMIN GUID}針對上述範例中的 和 {DEVELOPER GUID} 佔位符,您可以使用在線 GUID 產生器產生 GUID(適用於 “guid generator” 的 Google 搜尋結果)。

若要將角色指派給使用者 (或群組,如果您有進階層 Azure 帳戶的話):

  1. 瀏覽至 Azure 入口網站ME-ID 區域中的 企業應用程式
  2. 選取 app。 從資訊看板中選取 [管理]>[使用者和群組]
  3. 選取一或多個使用者帳戶的核取方塊。
  4. 從使用者清單上方的功能表中,選取 [編輯指派]
  5. 針對 [選取角色] 項目,選取 [未選取任何項目]
  6. 從清單中選擇角色,並使用 [選取] 按鈕來選取該角色。
  7. 使用畫面底部的 [指派] 按鈕來指派角色。

您可以在 Azure 入口網站中指派多個角色,方法是針對每個額外的角色指派「重新新增一個使用者」。 使用使用者清單頂端的 [新增使用者/群組] 按鈕來重新新增使用者。 使用上述步驟將另一個角色指派給使用者。 您可以視需要重複此流程多次,將額外的角色新增至使用者 (或群組)。

自訂使用者帳戶區段中顯示的 CustomAccountFactory 會設定為針對具有 JSON 陣列值的 role 宣告採取行動。 在用戶端應用程式中新增並註冊 CustomAccountFactory,如 [自訂使用者帳戶] 區段所示。 不需要提供程式碼來移除原始 role 宣告,因為架構會自動將其移除。

用戶端應用程式的 Program 檔案中,將名為「appRole」的宣告指定為 ClaimsPrincipal.IsInRole 檢查的角色宣告:

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

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

注意

如果您偏好使用 directoryRoles 宣告 (ADD 管理員角色),請將「directoryRoles」指派給 RemoteAuthenticationUserOptions.RoleClaim

伺服器應用程式的 Program 檔案中,將名為「http://schemas.microsoft.com/ws/2008/06/identity/claims/role」的宣告指定為 ClaimsPrincipal.IsInRole 檢查的角色宣告:

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

注意

註冊單一驗證配置時,驗證配置會自動用作應用程式的預設配置,而且不需要向 AddAuthentication 或透過 AuthenticationOptions 陳述該配置。 如需詳細資訊,請參閱 ASP.NET Core 驗證概觀ASP.NET Core 公告 (aspnet/Announcements #490)

注意

如果您偏好使用 wids 宣告 (ADD 管理員角色),請將「wids」指派給 TokenValidationParameters.RoleClaimType

在完成了上述步驟,以建立角色並將其指派給使用者 (或群組,如果您有進階層 Azure 帳戶的話),然後使用 Graph SDK 實作 CustomAccountFactory,如本文稍早所述和使用圖形 API 搭配 ASP.NET Core Blazor WebAssembly 中所述之後,對於已登入使用者獲指派的每個指派角色 (或指派給其所屬群組的角色),您應該會看到其 appRole 宣告。 使用測試使用者執行應用程式,以確認宣告如預期般存在。 在本機使用 Graph SDK 進行測試時,我們建議針對每個測試使用新的私人/incognito 瀏覽器工作模式,以防止徘徊的 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) 相同的角色。

Pascal 大小寫通常用於角色名稱 (例如 BillingAdministrator),但使用 Pascal 大小寫並非嚴格的需求。 允許不同的大小寫方案,如駝峰式大小寫、肉串式大小寫和蛇式大小寫。 在角色名稱中使用空格也是不尋常的,但允許。 例如, billing administrator 在 .NET 應用程式中是不尋常的角色名稱格式,但有效。

其他資源