Azure active directory ID令牌中缺少Azure AD v2.0特定的可选声明

Azure active directory ID令牌中缺少Azure AD v2.0特定的可选声明,azure-active-directory,asp.net-core-3.1,claims-authentication,Azure Active Directory,Asp.net Core 3.1,Claims Authentication,我正在尝试在NetCore3.1WebApp中使用Microsoft Identity Web-NuGet添加可选声明以进行用户身份验证。阅读MS文档,似乎只需要在Azure中的应用程序注册清单文件中声明可选声明。但是,当使用两个不同的应用程序(我自己的代码和一个MS项目示例)测试登录过程时,在成功登录后从Azure返回时,似乎没有将可选声明添加到ID令牌中,即在调试中查看令牌详细信息时,它们根本不存在 我不确定如何诊断此问题以及在何处跟踪问题,即我是否缺少Azure安装中所需的任何步骤 旁注:

我正在尝试在NetCore3.1WebApp中使用Microsoft Identity Web-NuGet添加可选声明以进行用户身份验证。阅读MS文档,似乎只需要在Azure中的应用程序注册清单文件中声明可选声明。但是,当使用两个不同的应用程序(我自己的代码和一个MS项目示例)测试登录过程时,在成功登录后从Azure返回时,似乎没有将可选声明添加到ID令牌中,即在调试中查看令牌详细信息时,它们根本不存在

我不确定如何诊断此问题以及在何处跟踪问题,即我是否缺少Azure安装中所需的任何步骤

旁注:为了确认我想要接收的是JWTID令牌,而不是用于调用图或其他Web API端点的jwt访问令牌

MS文档参考:

下面是清单文件的摘录:(注意,我甚至声明了“accessTokenAcceptedVersion”:2,因为我使用的可选声明在版本1中不可用,如果上述声明保留为默认的“null”值,那么Azure将假定我们使用的是旧版版本1-可能有问题)

从启动类中提取:

public void ConfigureServices(IServiceCollection services)
    {
        // Added to original .net core template.
        // ASP.NET Core apps access the HttpContext through the IHttpContextAccessor interface and 
        // its default implementation HttpContextAccessor. It's only necessary to use IHttpContextAccessor 
        // when you need access to the HttpContext inside a service.
        // Example usage - we're using this to retrieve the details of the currrently logged in user in page model actions.
        services.AddHttpContextAccessor();

        // DO NOT DELETE (for now...)
        // This 'Microsoft.AspNetCore.Authentication.AzureAD.UI' library was originally used for Azure Ad authentication 
        // before we implemented the newer Microsoft.Identity.Web and Microsoft.Identity.Web.UI NuGet packages. 
        // Note after implememting the newer library for authetication, we had to modify the _LoginPartial.cshtml file.
        //services.AddAuthentication(AzureADDefaults.AuthenticationScheme)
        //    .AddAzureAD(options => Configuration.Bind("AzureAd", options));

        ///////////////////////////////////

        // Add services required for using options.
        // e.g used for calling Graph Api from WebOptions class, from config file.
        services.AddOptions();

        // Add service for MS Graph API Service Client.
        services.AddTransient<OidcConnectEvents>();

        // Sign-in users with the Microsoft identity platform
        services.AddSignIn(Configuration);

        // Token acquisition service based on MSAL.NET
        // and chosen token cache implementation
        services.AddWebAppCallsProtectedWebApi(Configuration, new string[] { Constants.ScopeUserRead })
            .AddInMemoryTokenCaches();

        // Add the MS Graph SDK Client as a service for Dependancy Injection.
        services.AddGraphService(Configuration);

        ///////////////////////////////////

        // The following lines code instruct the asp.net core middleware to use the data in the "roles" claim in the Authorize attribute and User.IsInrole()
        // See https://docs.microsoft.com/aspnet/core/security/authorization/roles?view=aspnetcore-2.2 for more info.
        services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
        {
            // The claim in the Jwt token where App roles are available.
            options.TokenValidationParameters.RoleClaimType = "roles";
        });

        // Adding authorization policies that enforce authorization using Azure AD roles. Polices defined in seperate classes.
        services.AddAuthorization(options =>
        {
            options.AddPolicy(AuthorizationPolicies.AssignmentToViewLogsRoleRequired, policy => policy.RequireRole(AppRole.ViewLogs));
        });

        ///////////////////////////////////

        services.AddRazorPages().AddMvcOptions(options =>
        {
            var policy = new AuthorizationPolicyBuilder()
                .RequireAuthenticatedUser()
                .Build();
            options.Filters.Add(new AuthorizeFilter(policy));
        }).AddMicrosoftIdentityUI();

        // Adds the service for creating the Jwt Token used for calling microservices.
        // Note we are using our independant bearer token issuer service here, NOT Azure AD
        services.AddScoped<JwtService>(); 
    }
更新

正在接近解决方案,但尚未完全达到。解决了两个问题:

  • 我最初在Azure中创建租户是为了使用B2C广告,尽管我不再使用B2C,并已切换到Azure广告。直到我删除了租户并创建了一个新租户,我才开始看到可选声明正确地传递到webapp。创建新租户并分配租户类型以使用Azure AD后,我发现“令牌配置”菜单现在可用于通过UI配置可选声明,似乎还需要修改应用程序清单,如上所示
  • 我必须将“profile”范围作为“delegate”类型添加到Azure中的webapp API权限中
  • 最后一个仍然没有解决的问题是,尽管我可以在调试期间看到存在的声明,但我不知道如何检索声明值

    在下面的方法中,我可以在使用Debug时看到所需的声明,但不知道如何检索值:

    public void OnGet()
        {
            var username = HttpContext.User.Identity.Name;
    
            var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
            var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "family_name")?.Value;
    
            _logger.LogInformation("" + username + " requested the Index page");
        }
    
    调试屏幕截图显示了给定的\u名称和族\u名称:


    我尝试了不同的代码示例,使用声明主体尝试获取值,但没有任何东西对我有效。希望这最后一个谜语对了解所需语法的人来说相当简单,正如前面所说,我们现在有了所需的可选声明,只是不知道如何实际获取值。

    非常感谢“Dhivya G-MSFT Identity”的帮助(见我原始问题下面的评论)下面的方法现在允许我从Azure成功登录后返回的令牌ID访问所需的声明值

        public void OnGet()
        {
            var username = HttpContext.User.Identity.Name;
    
            var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
            var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
    
            _logger.LogInformation("" + username + " requested the Index page");
        }
    

    根据权利要求,可选权利要求
    给定的\u名称
    家族\u名称
    需要
    配置文件
    范围。在令牌请求中,您是否指定了配置文件范围?您可以通过查看浏览器devTools中的HTTP流量来确认这一点。在API权限(Type=delegate)下向应用程序添加配置文件作用域后,我仍然无法使用。管理员同意也已授予。从devTools中的HTTP流量请求中提取的内容为“id\u token&scope=openid%20profile%20offline\u access%20User.Read&response…”类型名称为
    http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname
    不仅仅是姓氏,还可以使用.NET framework ClaimTypes类。您可以使用
    HttpContext.User.Claims.FirstOrDefault(c=>c.Type==System.Security.Claims.ClaimTypes.姓氏)?.Value
    ;有关更多信息,请参阅。非常感谢您的帮助,此功能正在运行。
    public void OnGet()
        {
            var username = HttpContext.User.Identity.Name;
    
            var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "given_name")?.Value;
            var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == "family_name")?.Value;
    
            _logger.LogInformation("" + username + " requested the Index page");
        }
    
        public void OnGet()
        {
            var username = HttpContext.User.Identity.Name;
    
            var forename = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.GivenName)?.Value;
            var surname = HttpContext.User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.Surname)?.Value;
    
            _logger.LogInformation("" + username + " requested the Index page");
        }