如何让Azure Active Directory应用角色显示在Claims中?(Umbraco 11)
解决Umbraco 11 Azure AD应用角色映射到用户组问题
核心问题分析
你当前使用MicrosoftAccount认证方案适配Azure AD,该方案主要面向个人微软账户,无法正确获取Azure AD自定义应用角色(roles声明)。需切换为OpenIdConnect方案,并配置正确的声明映射与权限范围,才能在authorization_code流程中获取到角色信息。
步骤1:替换认证方案为OpenIdConnect
修改UmbracoBuilderExtensions中的认证配置,将AddMicrosoftAccount替换为AddOpenIdConnect,并配置Azure AD专属参数:
namespace Example.Api.Features.Authentication.Extensions; public static class UmbracoBuilderExtensions { public static IUmbracoBuilder ConfigureAuthentication(this IUmbracoBuilder builder) { builder.Services.ConfigureOptions<OpenIdConnectBackOfficeExternalLoginProviderOptions>(); builder.AddBackOfficeExternalLogins(logins => { const string schema = OpenIdConnectDefaults.AuthenticationScheme; logins.AddBackOfficeLogin( backOfficeAuthenticationBuilder => { backOfficeAuthenticationBuilder.AddOpenIdConnect( backOfficeAuthenticationBuilder.SchemeForBackOffice(OpenIdConnectBackOfficeExternalLoginProviderOptions.SchemeName) ?? string.Empty, options => { options.CallbackPath = "/umbraco-signin-microsoft/"; options.ClientId = "CLIENT_ID"; options.ClientSecret = "CLIENT_SECRET"; // 设置Azure AD租户权威地址 options.Authority = "https://login.microsoftonline.com/TENANT/v2.0"; // 必须包含roles scope以获取应用角色声明 options.Scope.Add("roles"); options.Scope.Add("openid"); options.Scope.Add("profile"); options.Scope.Add("email"); // 映射roles声明,确保不被默认过滤 options.ClaimActions.MapJsonKey("roles", "roles"); options.TokenValidationParameters = new TokenValidationParameters { NameClaimType = "name", RoleClaimType = "roles" }; // 启用授权码流程 options.ResponseType = OpenIdConnectResponseType.Code; }); }); }); return builder; } }
步骤2:在自动关联回调中映射角色到Umbraco用户组
修改OpenIdConnectBackOfficeExternalLoginProviderOptions中的OnAutoLinking和OnExternalLogin方法,读取roles声明并同步到Umbraco用户组:
namespace Example.Api.Features.Configuration; public class OpenIdConnectBackOfficeExternalLoginProviderOptions : IConfigureNamedOptions<BackOfficeExternalLoginProviderOptions> { public const string SchemeName = "OpenIdConnect"; public void Configure(string name, BackOfficeExternalLoginProviderOptions options) { if (name != "Umbraco." + SchemeName) { return; } Configure(options); } public void Configure(BackOfficeExternalLoginProviderOptions options) { options.AutoLinkOptions = new ExternalSignInAutoLinkOptions( autoLinkExternalAccount: true, defaultUserGroups: Array.Empty<string>(), // 不再使用默认组,完全由Azure角色控制 allowManualLinking: false ) { OnAutoLinking = (autoLinkUser, loginInfo) => { autoLinkUser.IsApproved = true; // 清空默认组,根据Azure角色分配Umbraco组 autoLinkUser.UserGroups.Clear(); var azureRoles = loginInfo.Principal.Claims .Where(c => c.Type == "roles") .Select(c => c.Value); foreach (var role in azureRoles) { switch (role) { case "Administrator": autoLinkUser.UserGroups.Add(Constants.Security.AdminGroupAlias); break; case "Editor": autoLinkUser.UserGroups.Add(Constants.Security.EditorGroupAlias); break; // 可添加更多角色映射 } } }, OnExternalLogin = (user, loginInfo) => { // 每次登录同步角色 user.UserGroups.Clear(); var azureRoles = loginInfo.Principal.Claims .Where(c => c.Type == "roles") .Select(c => c.Value); foreach (var role in azureRoles) { switch (role) { case "Administrator": user.UserGroups.Add(Constants.Security.AdminGroupAlias); break; case "Editor": user.UserGroups.Add(Constants.Security.EditorGroupAlias); break; } } return true; } }; options.DenyLocalLogin = true; options.AutoRedirectLoginToExternalProvider = true; } }
步骤3:Azure端配置验证
- 应用注册Manifest检查:确保
appRoles的allowedMemberTypes包含"User",示例:"appRoles": [ { "allowedMemberTypes": ["User"], "description": "Umbraco管理员", "displayName": "Administrator", "id": "你的角色ID", "isEnabled": true, "value": "Administrator" } ] - API权限配置:在应用注册的「API权限」中添加自身应用的权限(选择「我的API」→ 勾选
roles权限),并点击「授予管理员同意」。 - 企业应用角色分配:确认已在企业应用中将角色分配给对应用户。
验证方式
登录Umbraco后台后,解码ID Token(可使用JWT解码工具),确认roles字段已包含分配的应用角色;同时检查Umbraco用户的组是否与Azure角色匹配。
内容的提问来源于stack exchange,提问作者0Neji
相关产品推荐
相关产品推荐

