Microsoft Entra (ME-ID) 组、管理员角色和应用角色

注意

此版本不是本文的最新版本。 对于当前版本,请参阅此文的 .NET 8 版本

重要

此信息与预发布产品相关,相应产品在商业发布之前可能会进行重大修改。 Microsoft 对此处提供的信息不提供任何明示或暗示的保证。

对于当前版本,请参阅此文的 .NET 8 版本

本文介绍如何配置 Blazor WebAssembly 以使用 Microsoft Entra ID 组和角色。

Microsoft Entra (ME-ID) 提供了多种授权方法,这些方法可与 ASP.NET Core Identity 结合使用:

    • 安全性
    • Microsoft 365
    • 分布
  • 角色
    • ME-ID 管理员角色
    • 应用角色

本文中的指南适用于以下主题中所述的 Blazor WebAssembly ME-ID 部署方案:

本文的指南提供了有关客户端和服务器应用的说明:

  • 客户端:独立Blazor WebAssembly应用。
  • 服务器:ASP.NET 核心服务器 API/Web API 应用。 对于独立 Blazor WebAssembly 应用,可以忽略整个文章中的 SERVER 指南。
  • 客户端:独立 Blazor WebAssembly 应用或托管的 Blazor解决方案Client 应用。
  • 服务器:ASP.NET Core 服务器 API/Web API 应用或托管 Blazor 解决方案的 Server 应用。 对于独立 Blazor WebAssembly 应用,可以忽略整个文章中的 SERVER 指南。

本文中的示例会利用新的 .NET/C# 功能。 使用 .NET 7 或更早版本中的示例时,需要稍作修改。 但是,与 ME-ID 和 Microsoft Graph 交互有关的文本和代码示例对所有版本的 ASP.NET Core 都是相同的。

先决条件

本文中的指南根据将图形 API 与 ASP.NET Core Blazor WebAssembly 配合使用中的 Graph SDK 指南实现 Microsoft Graph API。 按照 Graph SDK 实现指南配置应用并对其进行测试,以确认应用可以获取测试用户帐户的图形 API 数据。 此外,请参阅图形 API 文章的安全文章交叉链接,以查看 Microsoft Graph 安全概念。

在本地使用 Graph SDK 进行测试时,建议为每个测试使用一个新的专用/隐身浏览器会话,防止 cookie 干扰测试的情况继续存在。 有关详细信息,请参阅使用 Microsoft Entra ID 保护 ASP.NET Core Blazor WebAssembly 独立应用

作用域

若要允许 Microsoft Graph API 调用用户配置文件、角色分配和组成员身份数据:

  • 在 Azure 门户中,CLIENT 应用配置了委托 User.Read 范围 (https://graph.microsoft.com/User.Read),因为读取用户数据的访问权限由授予(委托)给单个用户的范围决定
  • 在 Azure 门户中,SERVER 应用配置了应用程序 GroupMember.Read.All 范围 (https://graph.microsoft.com/GroupMember.Read.All),因为访问权限是为了让应用获取有关组成员身份的信息,而不是基于单个用户授权来访问有关组成员的数据

除了前面列出的主题(包括 Microsoft 帐户的独立产品或包含 ME-ID 的独立产品)介绍的 ME-ID 部署方案中所需的作用域外,还需要上述作用域。

除了前面列出的主题(包括 Microsoft 帐户的独立产品、包含 ME-ID 的独立产品和由 ME-ID 托管)介绍的 ME-ID 部署方案中所需的作用域外,还需要上述作用域。

有关详细信息,请参阅 Microsoft 标识平台中的权限和同意概述以及 Microsoft Graph 权限概述

注意

“权限”和“作用域”术语在 Azure 门户和各种 Microsoft 和外部文档集中均可互换使用。 本文为针对在 Azure 门户中分配给应用的权限通篇使用“作用域”一词。

组成员身份声明属性

在 Azure 门户的 CLIENT 和 SERVER 应用的应用清单中,将 groupMembershipClaims 属性设置为 All。 值为 All 会导致 ME-ID 在已知 ID 声明 (wids) 中发送已登录用户的所有安全组、通讯组和角色:

  1. 打开应用的 Azure 门户注册。
  2. 在边栏中选择“管理”>“清单”。
  3. 查找 groupMembershipClaims 属性。
  4. 将值设置为 All ("groupMembershipClaims": "All")。
  5. 如果进行了更改,请选择“保存”按钮。

自定义用户帐户

将用户分配到 Azure 门户中的 ME-ID 安全组和 ME-ID 管理员角色。

本文中的示例:

  • 假设将用户分配到 Azure 门户 ME-ID 租户中的 ME-ID 计费管理员角色,以授权访问服务器 API 数据。
  • 使用授权策略在 CLIENT 和 SERVER 应用中控制访问。

在 CLIENT 应用中,将 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 的 CLIENT 应用添加包引用。

注意

有关将包添加到 .NET 应用的指南,请参阅包使用工作流(NuGet 文档)中“安装和管理包”下的文章。 在 NuGet.org 中确认正确的包版本。

将图形 API 与 ASP.NET Core Blazor WebAssembly 一起使用一文的 Graph SDK 部分中,添加 Graph SDK 实用工具类和配置。 指定 User.Read 访问令牌的作用域,如文章的示例 wwwroot/appsettings.json 文件中所示。

将以下自定义用户帐户工厂添加到 CLIENT 应用。 自定义用户工厂用于建立以下内容:

  • 应用角色声明 (appRole)(包含在应用角色部分)。
  • ME-ID 管理员角色声明 (directoryRole)。
  • 用户移动电话号码的示例用户配置文件数据声明 (mobilePhone) 和办公地点 (officeLocation)。
  • ME-ID 组声明 (directoryGroup)。
  • ILogger (logger),便于你要记录信息或错误时使用。

CustomAccountFactory.cs

以下示例假设项目的应用设置文件包含基 URL 的条目:

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

在前面的示例中,{VERSION} 占位符是 MS 图形 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 标识平台返回的 GUID 值为 ME-ID 管理员角色实体 ID,而不是角色模板 ID 实体 ID 在 Microsoft 标识平台的租户中不稳定,因此不应用于为应用中的用户创建授权策略。 始终使用 wids 声明提供的 ME-ID 管理员角色的角色模板 ID

在 CLIENT 应用中,将 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>();

确认是否存在将图形 API 与 ASP.NET Core Blazor WebAssembly 一起使用一文中所述的 Graph SDK 代码,并根据 Graph SDK 指南确认 wwwroot/appsettings.json 配置是否正确:

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

授权配置

客户端应用中,为每个应用角色、ME-ID 管理员角色或 Program 文件中的安全组创建策略。 以下示例为 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 中基于策略的授权

在以下示例中,CLIENT 应用使用前面的策略来授权用户。

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

当访问令牌包含 groupswidsrole 声明时,SERVER API 应用可以通过授权策略授权用户访问安全组、ME-ID 管理员角色和应用角色的安全 API 终结点。 下面的示例使用 wids(已知 ID/角色模板 ID)声明,在 Program 文件中为 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 中基于策略的授权

对 SERVER 应用中的控制器的访问可以基于将 [Authorize] 属性 与策略名称(API 文档:AuthorizeAttribute)结合使用。

下面的示例使用名为 BillingAdministrator 的策略,对 BillingDataController 中计费数据的访问限制为 Azure 计费管理员:

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

有关详细信息,请参阅 ASP.NET Core 中基于策略的授权

应用角色

要在 Azure 门户中配置应用以提供应用角色成员资格声明,请参阅 Entra 文档中的在应用程序中添加应用角色并在令牌中接收这些角色

下面的示例假定 CLIENT 和 SERVER 应用配置了两个角色,并将角色分配给测试用户:

  • Admin
  • Developer

注意

当开发独立应用的客户端服务器对(独立 Blazor WebAssembly 应用和 ASP.NET Core 服务器 API/Web API 应用)时,客户端和服务器 Azure 门户应用注册的 appRoles 清单属性必须包含相同的已配置角色。 在客户端应用清单中建立角色后,请将它们全部复制到服务器应用清单中。 如果未在客户端和服务器应用注册之间映射清单 appRoles,则不会为服务器 API/Web API 的经过身份验证的用户建立角色声明,即使其访问令牌在 role 声明中具有正确的实体也是如此。

注意

当开发托管 Blazor WebAssembly 应用或独立应用的客户端服务器对(独立 Blazor WebAssembly 应用和 ASP.NET Core 服务器 API/Web API 应用)时,客户端和服务器 Azure 门户应用注册的 appRoles 清单属性必须包含相同的已配置角色。 在客户端应用清单中建立角色后,请将它们全部复制到服务器应用清单中。 如果未在客户端和服务器应用注册之间映射清单 appRoles,则不会为服务器 API/Web API 的经过身份验证的用户建立角色声明,即使其访问令牌在 role 声明中具有正确的实体也是如此。

尽管无法将角色分配给没有 Microsoft Entra ID Premium 帐户的组,但你可以将角色分配给用户,并为具有标准 Azure 帐户的用户接收 role 声明。 本部分中的指南不需要 ME-ID Premium 帐户。

如果你有高级层 Azure 帐户,“管理”>“应用角色”将显示在Azure 门户应用注册边栏中。 按照在应用程序中添加应用角色并在令牌中接收这些角色中的指导来配置应用的角色。

如果没有高级层 Azure 帐户,请在 Azure 门户中编辑应用的清单。 按照应用程序角色:实现中的指导,在清单文件的 appRoles 条目中手动建立应用的角色。 保存对文件所做的更改。

下面是创建 AdminDeveloper 角色的示例 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"
  }
],

若要将角色分配给用户(或组,如果你有高级层 Azure 帐户),请执行以下操作:

  1. 导航到 Azure 门户的 ME-ID 区域中的“企业应用程序”。
  2. 选择应用。 从边栏中选择“管理”>“用户和组”。
  3. 选中一个或多个用户帐户的复选框。
  4. 在用户列表上方的菜单中,选择“编辑分配”。
  5. 对于“选择角色”条目,选择“未选择任何项”。
  6. 从列表中选择一个角色,并使用“选择”按钮将其选中。
  7. 使用屏幕底部的“分配”按钮分配角色。

通过为其他每个角色分配重新添加用户,在 Azure 门户中分配多个角色。 使用用户列表顶部的“添加用户/组”按钮重新添加用户。 使用上述步骤向用户分配另一个角色。 可以根据需要多次重复此过程,将其他角色添加到用户(或组)。

自定义用户帐户部分中显示的 CustomAccountFactory 设置为使用 JSON 数组值应对 role 声明。 在 CLIENT 应用中添加并注册 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 进行测试时,建议为每个测试使用一个新的专用/隐身浏览器会话,防止 cookie 干扰测试的情况继续存在。 有关详细信息,请参阅使用 Microsoft Entra ID 保护 ASP.NET Core Blazor WebAssembly 独立应用

组件授权方法此时有效。 CLIENT 应用的组件中的任何授权机制都可以使用 Admin 角色来授权用户:

支持多个角色测试:

  • 要求用户为 AdminDeveloper 角色,并具有 AuthorizeView 组件:

    <AuthorizeView Roles="Admin, Developer">
        ...
    </AuthorizeView>
    
  • 要求用户同时为 AdminDeveloper 角色,并具有 AuthorizeView 组件

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

    有关 ContextAuthorizeView 内部的详细信息,请参阅 ASP.NET Core Blazor身份验证和授权

  • 要求用户为 AdminDeveloper 角色,并具有 [Authorize] 属性

    @attribute [Authorize(Roles = "Admin, Developer")]
    
  • 要求用户为 AdminDeveloper 角色,并具有 [Authorize] 属性:

    @attribute [Authorize(Roles = "Admin")]
    @attribute [Authorize(Roles = "Developer")]
    
  • 要求用户为 AdminDeveloper 角色,并具有过程代码:

    @code {
        private async Task DoSomething()
        {
            var authState = await AuthenticationStateProvider
                .GetAuthenticationStateAsync();
            var user = authState.User;
    
            if (user.IsInRole("Admin") || user.IsInRole("Developer"))
            {
                ...
            }
            else
            {
                ...
            }
        }
    }
    
  • 要求用户同时为 AdminDeveloper 角色,并具有过程代码,方法是将 条件 OR (||) 更改为上述示例中的 条件 AND (&&)

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

SERVER 应用的控制器中的任何授权机制都可以使用 Admin 角色来授权用户:

支持多个角色测试:

  • 要求用户为 AdminDeveloper 角色,并具有 [Authorize] 属性:

    [Authorize(Roles = "Admin, Developer")]
    
  • 要求用户为 AdminDeveloper 角色,并具有 [Authorize] 属性:

    [Authorize(Roles = "Admin")]
    [Authorize(Roles = "Developer")]
    
  • 要求用户为 AdminDeveloper 角色,并具有过程代码:

    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 ...
    }
    
  • 要求用户同时为 AdminDeveloper 角色,并具有过程代码,方法是将 条件 OR (||) 更改为上述示例中的 条件 AND (&&)

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

由于 .NET 字符串比较默认区分大小写,因此匹配的角色名称也区分大小写。 例如,Admin(大写 A)不被视为与 admin(小写 a)相同的角色。

Pascal 大小写通常用于角色名称(例如 BillingAdministrator),但使用 Pascal 大小写并非严格要求。 允许不同的包装方案,如骆驼元素、烤肉元素和蛇元素。 在角色名称中使用空格也是不常见的,但允许使用。 例如,billing administrator 在 .NET 应用中是一种不常见的角色名称格式,但有效。

其他资源