Microsoft Identity Platform Azure AD App Role 在 NET Core 3.1 Razor Pages 中不起作用
Microsoft Identity Platform Azure AD App Role not working in NET Core 3.1 Razor Pages
-
authorization
-
azure-active-directory
-
.net-core-authorization
-
microsoft-identity-platform
-
.net-core-3.1
我一直在关注最近的一个 MS 项目示例:https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/5-WebApp-AuthZ/5-1-Roles
我找不到 Razor 项目的任何示例,只有 MVC 因此移植了我认为支持使用 Azure AD 应用程序角色并使用与项目示例中相同的 AuthorizationPolicyBuilder 库进行授权所需的所有内容。
我通过更新应用程序清单文件并将用户分配给此 Web 应用程序所需的角色,在 Azure AD 中创建了一个应用程序角色。我相信我已经涵盖了 Azure 中所需的步骤,因为我可以清楚地看到所需的角色 'ViewLogs' 包含在成功登录后从 Azure 返回的 ID 令牌中。
问题是一个受 'ViewLogs' 授权策略保护的页面,每次我尝试加载该页面时都会给我一条访问被拒绝的消息。我不确定如何诊断此问题以了解为什么它不允许我进入。
Startup.cs
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.AssignmentToUserReaderRoleRequired, policy => policy.RequireRole(AppRole.UserReaders));
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>();
}
AppRole Class.cs
/// <summary>
/// Contains a list of all the Azure AD app roles this app depends on and works with.
/// </summary>
public static class AppRole
{
/// <summary>
/// User readers can read basic profiles of all users in the directory.
/// </summary>
public const string UserReaders = "UserReaders";
/// <summary>
/// View Logs can review system logs and run all log queries.
/// </summary>
public const string ViewLogs = "ViewLogs";
}
/// <summary>
/// Wrapper class the contain all the authorization policies available in this application.
/// </summary>
public static class AuthorizationPolicies
{
public const string AssignmentToUserReaderRoleRequired = "AssignmentToUserReaderRoleRequired";
public const string AssignmentToViewLogsRoleRequired = "AssignmentToViewLogsRoleRequired";
}
我想访问的页面:
//[Authorize]
//[AllowAnonymous]
[Authorize(Policy = AuthorizationPolicies.AssignmentToViewLogsRoleRequired)] // Not working
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public readonly JwtService _jwtService;
public IndexModel(ILogger<IndexModel> logger, JwtService jwtService)
{
_logger = logger;
_jwtService = jwtService;
}
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");
}
public JsonResult OnGetJwtToken()
{
var token = _jwtService.GenerateSecurityToken();
return new JsonResult(token);
}
}
提前致谢...
我从另一个线程中找到了一个片段,它为我提供了找到解决方案的线索。在使用策略实现授权时,使用成功登录后从 Azure 返回的 ID 令牌中的声明,Razor 和带控制器的 MVC 之间似乎存在一些细微差别。我发现我无法使用具有“RequireRole”语法的相同授权策略。但是使用“RequireClaim”似乎解决了这个问题。
我的 Startup.cs 文件中的修改代码:
// Adding authorization policies that enforce authorization using Azure AD roles. Polices defined in seperate classes.
services.AddAuthorization(options =>
{
// This line may not work for razor at all, haven't tried it but is what was used in MVC from the MS Project example.
options.AddPolicy(AuthorizationPolicies.AssignmentToUserReaderRoleRequired, policy => policy.RequireRole(AppRole.UserReaders));
// NOTE BELOW - I had to change the syntax from RequireRole to RequireClaim
options.AddPolicy(AuthorizationPolicies.AssignmentToViewLogsRoleRequired, policy => policy.RequireClaim(ClaimTypes.Role, AppRole.ViewLogs));
});
使用的其余代码和过程与我最初提出的问题并没有改变,最终使它起作用。希望这可以帮助其他遇到类似问题的人...
authorization
azure-active-directory
.net-core-authorization
microsoft-identity-platform
.net-core-3.1
我一直在关注最近的一个 MS 项目示例:https://github.com/Azure-Samples/active-directory-aspnetcore-webapp-openidconnect-v2/tree/master/5-WebApp-AuthZ/5-1-Roles
我找不到 Razor 项目的任何示例,只有 MVC 因此移植了我认为支持使用 Azure AD 应用程序角色并使用与项目示例中相同的 AuthorizationPolicyBuilder 库进行授权所需的所有内容。
我通过更新应用程序清单文件并将用户分配给此 Web 应用程序所需的角色,在 Azure AD 中创建了一个应用程序角色。我相信我已经涵盖了 Azure 中所需的步骤,因为我可以清楚地看到所需的角色 'ViewLogs' 包含在成功登录后从 Azure 返回的 ID 令牌中。
问题是一个受 'ViewLogs' 授权策略保护的页面,每次我尝试加载该页面时都会给我一条访问被拒绝的消息。我不确定如何诊断此问题以了解为什么它不允许我进入。
Startup.cs
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.AssignmentToUserReaderRoleRequired, policy => policy.RequireRole(AppRole.UserReaders));
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>();
}
AppRole Class.cs
/// <summary>
/// Contains a list of all the Azure AD app roles this app depends on and works with.
/// </summary>
public static class AppRole
{
/// <summary>
/// User readers can read basic profiles of all users in the directory.
/// </summary>
public const string UserReaders = "UserReaders";
/// <summary>
/// View Logs can review system logs and run all log queries.
/// </summary>
public const string ViewLogs = "ViewLogs";
}
/// <summary>
/// Wrapper class the contain all the authorization policies available in this application.
/// </summary>
public static class AuthorizationPolicies
{
public const string AssignmentToUserReaderRoleRequired = "AssignmentToUserReaderRoleRequired";
public const string AssignmentToViewLogsRoleRequired = "AssignmentToViewLogsRoleRequired";
}
我想访问的页面:
//[Authorize]
//[AllowAnonymous]
[Authorize(Policy = AuthorizationPolicies.AssignmentToViewLogsRoleRequired)] // Not working
public class IndexModel : PageModel
{
private readonly ILogger<IndexModel> _logger;
public readonly JwtService _jwtService;
public IndexModel(ILogger<IndexModel> logger, JwtService jwtService)
{
_logger = logger;
_jwtService = jwtService;
}
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");
}
public JsonResult OnGetJwtToken()
{
var token = _jwtService.GenerateSecurityToken();
return new JsonResult(token);
}
}
提前致谢...
我从另一个线程中找到了一个片段,它为我提供了找到解决方案的线索。在使用策略实现授权时,使用成功登录后从 Azure 返回的 ID 令牌中的声明,Razor 和带控制器的 MVC 之间似乎存在一些细微差别。我发现我无法使用具有“RequireRole”语法的相同授权策略。但是使用“RequireClaim”似乎解决了这个问题。
我的 Startup.cs 文件中的修改代码:
// Adding authorization policies that enforce authorization using Azure AD roles. Polices defined in seperate classes.
services.AddAuthorization(options =>
{
// This line may not work for razor at all, haven't tried it but is what was used in MVC from the MS Project example.
options.AddPolicy(AuthorizationPolicies.AssignmentToUserReaderRoleRequired, policy => policy.RequireRole(AppRole.UserReaders));
// NOTE BELOW - I had to change the syntax from RequireRole to RequireClaim
options.AddPolicy(AuthorizationPolicies.AssignmentToViewLogsRoleRequired, policy => policy.RequireClaim(ClaimTypes.Role, AppRole.ViewLogs));
});
使用的其余代码和过程与我最初提出的问题并没有改变,最终使它起作用。希望这可以帮助其他遇到类似问题的人...