我需要构建一个使用.NET6的ASP.NET Core Web应用程序。我已经在GitHub上遵循了Azure-Sample存储库中的说明:
我已经调整了appsettings.json文件中的AzureAd部分:
"AzureAd": {
"ClientId": "my-client-guid",
"TenantId": "my-tenant-guid",
"Domain": "my-tenant-name",
"ClientSecret": "my-client-secret-guid",
"Instance": "https://login.microsoftonline.com/",
"Scopes": "user.read,profile,openid",
"ClientCapabilities": [ "cp1" ],
"CallbackPath": "/signin-oidc"
}
- ClientId和TenantId字段从Azure门户AD应用程序面板中获取,我在该面板上创建了应用程序注册。在此应用程序的详细信息页面上是概览面板 - 提供ClientId、TenantId的参考。
- ClientSecret也是在同一页面上创建的,在证书和密码面板上。
- 域名由Azure域名列表面板提供。
用户角色(读取器/管理员)是在上述(Azure AD应用程序)页面上创建的。
仍然在同一页上:
- 身份验证选项卡中添加了一个新的Web平台,重定向URI为https://localhost:7293/signin-oidc。对于前端通道注销,提供了https://localhost:44321/signout-oidc。
- ID Tokens在隐式授权和混合流程部分下被选中。
- 单租户选项(仅允许组织帐户)。
- 公共流程被禁用。
在企业应用程序中,我的应用程序已列出。在应用程序的详细信息视图中:
- 属性选项卡:分配要求设置为false。我不想将用户预分配给该应用程序。
- 对用户可见:设置为false。
- 用户和组选项卡:安全组已创建,角色(读取器/管理员)已分配给安全组。成员已分配到安全组。为了测试目的,我还添加了我的Azure AD用户,并赋予了读取器角色。
- 单点登录:这里我看到以下消息:在企业应用程序体验中,此应用程序的单点登录配置不可用。{{my-application-name}}是使用应用程序注册体验创建的
- 登录日志:奇怪的是,我在这里看到我的登录记录,因此我认为角色声明未转移到我的Web应用程序,因为在打开控制器视图时我收到未经授权的错误。
Web应用程序引用
我已将配置部分映射到一个模型中,以便在需要时注入为IOptionsMicrosoftGraphConfiguration,以映射GraphApiUrl:
public class MicrosoftGraphConfiguration
{
public const string ConfigurationName = "MicrosoftGraph";
public string? GraphApiUrl { get; set; }
}
AzureAdConfiguration 用于映射 AzureAd 配置。
public class AzureAdConfiguration
{
public const string ConfigurationName = "AzureAd";
public string? ClientId { get; set; }
public string? TenantId { get; set; }
public string? ClientSecret { get; set; }
public string? Domain { get; set; }
public string? Instance { get; set; }
public string? BaseUrl { get; set; }
public string[]? ClientCapabilities { get; set; }
public string[]? Scopes { get; set; }
public string? CallbackPath { get; set; }
}
Program.cs 用于配置和添加服务到 DI 容器中等。
var builder = WebApplication.CreateBuilder(args);
builder.Services.Configure<MicrosoftGraphConfiguration>(builder.Configuration.GetSection(MicrosoftGraphConfiguration.ConfigurationName));
builder.Services.Configure<AzureAdConfiguration>(builder.Configuration.GetSection(AzureAdConfiguration.ConfigurationName));
JwtSecurityTokenHandler.DefaultMapInboundClaims = false;
builder.Services.AddMicrosoftIdentityWebAppAuthentication(builder.Configuration, subscribeToOpenIdConnectMiddlewareDiagnosticsEvents: true)
.EnableTokenAcquisitionToCallDownstreamApi(new string[] { "User.Read" })
.AddInMemoryTokenCaches();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AssignmentToReaderRoleRequired", policy => policy.RequireRole("Reader"));
options.AddPolicy("AssignmentToAdminRoleRequired", policy => policy.RequireRole("Admin"));
});
builder.Services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
options.TokenValidationParameters.RoleClaimType = "roles";
});
// Add services to the container.
builder.Services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
}).AddMicrosoftIdentityUI();
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
用于测试目的的控制器操作:
[HttpGet]
public async Task<IActionResult> IndexAsync()
{
GetTenantDetailsResult tenantDetails = new();
if (this.tenantService != null)
{
tenantDetails = await this.tenantService.GetTenantDetailsAsync();
}
return View(new TenantViewModel(tenantDetails));
}
[HttpGet]
[Route("/Reader")]
[Authorize(Policy = AuthorizationPolicies.AssignmentToReaderRoleRequired)]
public IActionResult Reader()
{
var asd = User;
return Ok("He is a reader");
}
[HttpGet]
[Route("/Admin")]
[Authorize(Policy = AuthorizationPolicies.AssignmentToAdminRoleRequired)]
public IActionResult Admin()
{
return Ok("He is an admin");
}
打开应用程序(无cookie - 隐身)会将我重定向到https://login.microsoft.com/{my-tenantId}/oauth2/authorize?...。一旦登录,没有[Authorize(...)]属性的端点可以正常工作。
打开任何具有[Authorize]属性的上述端点都会给我HTTP 404并重定向到: https://localhost:7293/MicrosoftIdentity/Account/AccessDenied?ReturnUrl=%2Freader 根据文档,角色声明应与任何ID令牌一起发送。 “这些分配的应用程序角色包含在为应用程序发行的任何令牌中,无论是...还是在您的应用程序登录用户时的ID令牌。”
我不确定,因此我的问题是:
1. 角色声明未发送? 2. 发送了角色声明但无法解析 3. 如何进行调试以查找问题
作为奇怪的行为...如果我在隐身/InPrivate浏览器窗口中打开应用程序/Reader端点,则在以下错误详细信息之后,我会收到HTTP 500响应代码: MsalServiceException:配置问题正在阻止身份验证-检查服务器的错误消息以获取详细信息。您可以在应用程序注册门户中修改配置。请参见https://aka.ms/msal-net-invalid-client了解详细信息。原始异常:AADSTS7000215:提供的客户端密码无效。确保在请求中发送的密钥是客户端密码值,而不是添加到应用程序的客户端密码ID的密钥。
即使ClientSecret如上所述,我认为它是正确的。 Http 500的原因可能是当前我没有维护https://localhost:7293/signin-oidc的端点。
感谢帮助,因为我已经迷失了3天。