Мы хотим использовать собственный обработчик авторизации в ASP.NET Core 8.
При отладке я вижу, что код обработчика попадает в код и требование авторизации успешно выполнено, но затем я получаю 403, потому что DenyAnonymousAuthorizationRequirement PassthroughAuthorizationHandler не выполняется.
Но я прошел проверку подлинности, я вижу свое имя в пользовательском интерфейсе, и все остальное работает хорошо, включая атрибут [Authorize] с ролями, которые мы используем на других конечных точках. С пользовательским обработчиком это просто не работает.
Аутентификация настраивается следующим образом:
public static IServiceCollection ConfigureAuth(this IServiceCollection services) {
services
.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(CertificateAuthenticationDefaults.AuthenticationScheme,
options => {
options.Events = new CertificateAuthenticationEvents {
OnCertificateValidated = context => {
var userManager = context.HttpContext.RequestServices.GetRequiredService();
context.Principal = userManager.LoginUserWithCertificate(context
.ClientCertificate);
context.Success();
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
services.AddScoped();
return services;
}
Обработчик:
public class AppRolesAuthorizationHandler:AuthorizationHandler {
IHttpContextAccessor httpContextAccessor;
public AppRolesAuthorizationHandler(IHttpContextAccessor httpContextAccessor) {
this.httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
AppRolesAuthorizeAttribute requirement) {
string rolesString = requirement.Roles;
string[] roles = rolesString.Split(",");
foreach (string entry in roles) {
string role = entry.Trim();
if (!context.User.IsInRole(role)) {
continue;
}
if (role != Role.Project.ToString()) {
context.Succeed(requirement);
return Task.CompletedTask;
}
long appId = getAppId(context);
if (appId == -1) {
context.Fail();
return Task.CompletedTask;
}
User user = context.User as User;
App appFound = user.Apps.Find((app) => app.Id.Value == appId);
if (appFound != null) {
context.Succeed(requirement);
return Task.CompletedTask;
}
}
context.Fail();
return Task.CompletedTask;
}
private long getAppId(AuthorizationHandlerContext context) {
var routeData = httpContextAccessor.HttpContext.Request.RouteValues;
if (routeData.TryGetValue("appId", out object? appIdObj)) {
long appId = long.Parse(appIdObj.ToString());
return appId;
}
// no appId specified as request param, so this attribute was incorrectly used
throw new Exception("Only use AuthorizeAppApiAttribute on methods with 'appId' parameter.");
}
}
Program.cs:
using Hangfire;
using MMS.Core;
using MMS.Infrastructure;
using MMS.Web.Services;
var builder = WebApplication.CreateBuilder(args);
// Add and configure services to the container (IOC).
#region 3rd party service Configurations
builder.Configuration.AddEnvironmentVariables();
builder.Services.ConfigureConnectionStrings(builder.Configuration);
builder.Services.ConfigureThirdParties();
builder.Services.ConfigureUI();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.ConfigureValidation();
builder.Services.AddLogging(logging => logging.AddConsole());
#endregion
#region Domain Services
builder.Services.ConfigureWeb();
builder.Services.ConfigureInfrastructure(builder.Configuration);
builder.Services.ConfigureCore();
//Auth is configured last because we need the domain services to be registered first
builder.Services.ConfigureAuth();
builder.Services.ConfigureSerializationOptions();
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
#region Middlewares
if (!app.Environment.IsDevelopment()) {
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseWebOptimizer(); // WebOptimizer for Bundling the UI
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHangfireDashboard("/hangfire",
new DashboardOptions { Authorization = new[] { new HangfireAuthorizationFilter() } });
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.ConfigureErrorHandlingMiddleware();
});
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Apps}/{id=UrlParameter.Optional}");
app.MapFallbackToFile("index.html");
#endregion
app.Run();
Как видите, в Program.cs UseAuthentication() вызывается перед UseAuthorization(). (Извините, если код беспорядок, у меня не так уж много опыта в настройке такого проекта...)
Что мне здесь не хватает? Как я могу узнать, где именно что-то идет не так?
EDIT: Я подозреваю, что я что-то напутал в PolicyProvider. Но опять же, этот код, похоже, не попадает в отладку. Тогда как же вообще может работать обработчик?
public class AppRolesPolicyProvider: IAuthorizationPolicyProvider {
const string POLICY_PREFIX = "AppRoles";
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public AppRolesPolicyProvider(IOptions options)
{
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task GetDefaultPolicyAsync() =>
FallbackPolicyProvider.GetDefaultPolicyAsync();
public Task GetFallbackPolicyAsync() =>
Task.FromResult(null);
public Task GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase))
{
var roles = policyName.Substring(POLICY_PREFIX.Length);
var policy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddRequirements(new AppRolesRequirement(roles))
.Build();
return Task.FromResult(policy);
}
return Task.FromResult(null);
}
}
Фактическое использование в контроллере:
[HttpGet, Route("{appId:long}", Name = "GetApp")]
[AppRolesAuthorize("Assembly, Project, Viewer")]
public ActionResult Get(long appId) {
...
}
Подробнее здесь: https://stackoverflow.com/questions/793 ... -authoriza
Почему я получаю ошибку DenyAnonymousAuthorizationRequirement для своего настраиваемого обработчика авторизации в .NET 8 ⇐ C#
Место общения программистов C#
1771153140
Anonymous
Мы хотим использовать собственный обработчик авторизации в ASP.NET Core 8.
При отладке я вижу, что код обработчика попадает в код и требование авторизации успешно выполнено, но затем я получаю 403, потому что DenyAnonymousAuthorizationRequirement PassthroughAuthorizationHandler не выполняется.
Но я прошел проверку подлинности, я вижу свое имя в пользовательском интерфейсе, и все остальное работает хорошо, включая атрибут [Authorize] с ролями, которые мы используем на других конечных точках. С пользовательским обработчиком это просто не работает.
Аутентификация настраивается следующим образом:
public static IServiceCollection ConfigureAuth(this IServiceCollection services) {
services
.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddCertificate(CertificateAuthenticationDefaults.AuthenticationScheme,
options => {
options.Events = new CertificateAuthenticationEvents {
OnCertificateValidated = context => {
var userManager = context.HttpContext.RequestServices.GetRequiredService();
context.Principal = userManager.LoginUserWithCertificate(context
.ClientCertificate);
context.Success();
return Task.CompletedTask;
}
};
});
services.AddAuthorization();
services.AddScoped();
return services;
}
Обработчик:
public class AppRolesAuthorizationHandler:AuthorizationHandler {
IHttpContextAccessor httpContextAccessor;
public AppRolesAuthorizationHandler(IHttpContextAccessor httpContextAccessor) {
this.httpContextAccessor = httpContextAccessor;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
AppRolesAuthorizeAttribute requirement) {
string rolesString = requirement.Roles;
string[] roles = rolesString.Split(",");
foreach (string entry in roles) {
string role = entry.Trim();
if (!context.User.IsInRole(role)) {
continue;
}
if (role != Role.Project.ToString()) {
context.Succeed(requirement);
return Task.CompletedTask;
}
long appId = getAppId(context);
if (appId == -1) {
context.Fail();
return Task.CompletedTask;
}
User user = context.User as User;
App appFound = user.Apps.Find((app) => app.Id.Value == appId);
if (appFound != null) {
context.Succeed(requirement);
return Task.CompletedTask;
}
}
context.Fail();
return Task.CompletedTask;
}
private long getAppId(AuthorizationHandlerContext context) {
var routeData = httpContextAccessor.HttpContext.Request.RouteValues;
if (routeData.TryGetValue("appId", out object? appIdObj)) {
long appId = long.Parse(appIdObj.ToString());
return appId;
}
// no appId specified as request param, so this attribute was incorrectly used
throw new Exception("Only use AuthorizeAppApiAttribute on methods with 'appId' parameter.");
}
}
Program.cs:
using Hangfire;
using MMS.Core;
using MMS.Infrastructure;
using MMS.Web.Services;
var builder = WebApplication.CreateBuilder(args);
// Add and configure services to the container (IOC).
#region 3rd party service Configurations
builder.Configuration.AddEnvironmentVariables();
builder.Services.ConfigureConnectionStrings(builder.Configuration);
builder.Services.ConfigureThirdParties();
builder.Services.ConfigureUI();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.ConfigureValidation();
builder.Services.AddLogging(logging => logging.AddConsole());
#endregion
#region Domain Services
builder.Services.ConfigureWeb();
builder.Services.ConfigureInfrastructure(builder.Configuration);
builder.Services.ConfigureCore();
//Auth is configured last because we need the domain services to be registered first
builder.Services.ConfigureAuth();
builder.Services.ConfigureSerializationOptions();
#endregion
var app = builder.Build();
// Configure the HTTP request pipeline.
#region Middlewares
if (!app.Environment.IsDevelopment()) {
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
app.UseHttpsRedirection();
}
app.UseWebOptimizer(); // WebOptimizer for Bundling the UI
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseSwagger();
app.UseSwaggerUI();
app.UseHangfireDashboard("/hangfire",
new DashboardOptions { Authorization = new[] { new HangfireAuthorizationFilter() } });
app.UseExceptionHandler(exceptionHandlerApp =>
{
exceptionHandlerApp.ConfigureErrorHandlingMiddleware();
});
app.MapControllerRoute(name: "default",
pattern: "{controller=Home}/{action=Apps}/{id=UrlParameter.Optional}");
app.MapFallbackToFile("index.html");
#endregion
app.Run();
Как видите, в Program.cs UseAuthentication() вызывается перед UseAuthorization(). (Извините, если код беспорядок, у меня не так уж много опыта в настройке такого проекта...)
Что мне здесь не хватает? Как я могу узнать, где именно что-то идет не так?
EDIT: Я подозреваю, что я что-то напутал в PolicyProvider. Но опять же, этот код, похоже, не попадает в отладку. Тогда как же вообще может работать обработчик?
public class AppRolesPolicyProvider: IAuthorizationPolicyProvider {
const string POLICY_PREFIX = "AppRoles";
public DefaultAuthorizationPolicyProvider FallbackPolicyProvider { get; }
public AppRolesPolicyProvider(IOptions options)
{
FallbackPolicyProvider = new DefaultAuthorizationPolicyProvider(options);
}
public Task GetDefaultPolicyAsync() =>
FallbackPolicyProvider.GetDefaultPolicyAsync();
public Task GetFallbackPolicyAsync() =>
Task.FromResult(null);
public Task GetPolicyAsync(string policyName)
{
if (policyName.StartsWith(POLICY_PREFIX, StringComparison.OrdinalIgnoreCase))
{
var roles = policyName.Substring(POLICY_PREFIX.Length);
var policy = new AuthorizationPolicyBuilder()
.AddAuthenticationSchemes(CertificateAuthenticationDefaults.AuthenticationScheme)
.AddRequirements(new AppRolesRequirement(roles))
.Build();
return Task.FromResult(policy);
}
return Task.FromResult(null);
}
}
Фактическое использование в контроллере:
[HttpGet, Route("{appId:long}", Name = "GetApp")]
[AppRolesAuthorize("Assembly, Project, Viewer")]
public ActionResult Get(long appId) {
...
}
Подробнее здесь: [url]https://stackoverflow.com/questions/79346745/why-do-i-get-denyanonymousauthorizationrequirement-error-for-my-custom-authoriza[/url]
Ответить
1 сообщение
• Страница 1 из 1
Перейти
- Кемерово-IT
- ↳ Javascript
- ↳ C#
- ↳ JAVA
- ↳ Elasticsearch aggregation
- ↳ Python
- ↳ Php
- ↳ Android
- ↳ Html
- ↳ Jquery
- ↳ C++
- ↳ IOS
- ↳ CSS
- ↳ Excel
- ↳ Linux
- ↳ Apache
- ↳ MySql
- Детский мир
- Для души
- ↳ Музыкальные инструменты даром
- ↳ Печатная продукция даром
- Внешняя красота и здоровье
- ↳ Одежда и обувь для взрослых даром
- ↳ Товары для здоровья
- ↳ Физкультура и спорт
- Техника - даром!
- ↳ Автомобилистам
- ↳ Компьютерная техника
- ↳ Плиты: газовые и электрические
- ↳ Холодильники
- ↳ Стиральные машины
- ↳ Телевизоры
- ↳ Телефоны, смартфоны, плашеты
- ↳ Швейные машинки
- ↳ Прочая электроника и техника
- ↳ Фототехника
- Ремонт и интерьер
- ↳ Стройматериалы, инструмент
- ↳ Мебель и предметы интерьера даром
- ↳ Cантехника
- Другие темы
- ↳ Разное даром
- ↳ Давай меняться!
- ↳ Отдам\возьму за копеечку
- ↳ Работа и подработка в Кемерове
- ↳ Давай с тобой поговорим...
Мобильная версия