Почему я получаю ошибку DenyAnonymousAuthorizationRequirement для своего настраиваемого обработчика авторизации в .NET 8C#

Место общения программистов C#
Ответить
Anonymous
 Почему я получаю ошибку DenyAnonymousAuthorizationRequirement для своего настраиваемого обработчика авторизации в .NET 8

Сообщение 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) {
...
}


Подробнее здесь: https://stackoverflow.com/questions/793 ... -authoriza
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»