【发布时间】:2023-03-26 15:19:01
【问题描述】:
我正在尝试使用 Microsoft Identity Web - NuGet 添加可选声明,以在 NET Core 3.1 WebApp 中进行用户身份验证。阅读 MS Docs,似乎唯一需要的步骤是在 Azure 的应用注册清单文件中声明可选声明。但是,当使用两个不同的应用程序(我自己的代码和一个 MS 项目示例)测试登录过程时,在成功登录后从 Azure 返回时,似乎没有将可选声明添加到 ID 令牌中,即它们根本不存在在 Debug 中查看令牌详细信息时。
我不确定如何诊断此问题以及在何处跟踪问题,即我是否缺少 Azure 设置中的任何必需步骤?
旁注:只是为了确认它是我想要接收附加声明的 jwt ID 令牌,而不是用于调用图形或其他 Web API 端点的 jwt 访问令牌。
MS Docs 参考:v2.0-specific optional claims set
以下是 Manifest 文件的摘录:(请注意,我什至声明了“accessTokenAcceptedVersion”:2,因为我使用的可选声明在 ver.1 中不可用,如果上述内容保留为默认值'null' 值,然后 Azure 将假定我们使用的是旧版 1 - 可能的问题)
"accessTokenAcceptedVersion": 2,
"optionalClaims": {
"idToken": [
{
"name": "given_name",
"source": "user",
"essential": false,
"additionalProperties": []
},
{
"name": "family_name",
"source": "user",
"essential": false,
"additionalProperties": []
}
],
"accessToken": [],
"saml2Token": []
},
从启动类中提取:
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>();
}
示例 Razor PageModel 方法:
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");
}
更新
越来越接近解决方案,但还没有完全实现。解决了几个问题:
- 我最初在 Azure 中创建租户以使用 B2C AD,尽管我不再使用 B2C 并已切换到 Azure AD。直到我删除了租户并创建了一个新租户,我才开始看到可选声明正确地传递到 webapp。创建新租户并分配租户类型以使用 Azure AD 后,我发现“令牌配置”菜单现在可用于通过 UI 配置可选声明,似乎仍然需要修改 App 清单,如上图。
- 我必须将“配置文件”范围作为“委托”类型添加到 Azure 中的 webapp API 权限。
最后一个仍未解决的问题是,虽然我可以在 Debug 期间看到存在的声明,但我不知道如何检索声明值。
在下面的方法中,我可以在使用 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");
}
调试屏幕截图显示 given_name 和 family_name 存在:
我尝试了使用声明主体的不同代码示例来尝试获取值,但没有任何东西对我有用。希望这个最后的谜题对于知道所需语法的人来说相当简单,正如我们现在所说的,我们现在有所需的可选声明,只是不知道如何实际获取这些值。
【问题讨论】:
-
根据documentation 的可选声明
given_name和family_name需要profile范围。在您的令牌请求中,您是否指定了配置文件范围?您可以通过查看浏览器 devTools 中的 HTTP 流量来确认这一点。 -
在 API 权限(类型 = 委派)下将配置文件范围添加到应用程序后,我仍然无法正常工作。也已获得管理员同意。
-
从 devTools 中的 HTTP 流量请求中提取的是 'id_token&scope=openid%20profile%20offline_access%20User.Read&response...'
-
类型名称是
http://schemas.xmlsoap.org/ws/2005/05/identity/claims/surname不只是姓氏,您可以使用.NET 框架ClaimTypes 类。你可以使用HttpContext.User.Claims.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Surname)?.Value;更多信息可以参考documentation。 -
非常感谢您的帮助,现在正在运行。
标签: azure-active-directory asp.net-core-3.1 claims-authentication