Точка останова не попадает в AuthorizationFilterAttribute - PullRequest
1 голос
/ 15 мая 2019

У меня есть этот атрибут:

public class ValidateCertAttribute : AuthorizationFilterAttribute
{
    public override void OnAuthorization(HttpActionContext context)
    {
        // Read certificate from the HTTP Request and
        // check its various attributes against known
        // values from a config file.
        if (true) // certificate is invalid
        {
            context.Response = new HttpResponseMessage(HttpStatusCode.Forbidden)
            {
                ReasonPhrase = "Invalid certificate"
            };
        }
        else
        {
            base.OnAuthorization(context);
        }
    }
}

и это действие:

[HttpGet]
[Route("TestAuth")]
[ValidateCert]
public HttpResponseMessage TestAuth()
{
    return new HttpResponseMessage(HttpStatusCode.OK)
    {
        ReasonPhrase = "In Test method without any authorization."
    };
}

Это действие находится внутри контроллера .NET Core Web Api:

[ApiController]
public class TestAuthController : ControllerBase

С другой стороны, Startup.cs содержит:

app.UseMvc();

, поэтому это кажется странным, поскольку это должен быть просто контроллер Web Api, а не веб-приложение MVC.Хотя, по-видимому, это только для маршрутизации, но я подумал, что стоит упомянуть.

Я установил точку останова в первой строке кода атрибута, но это не ударил.Я полагаю, что это должно произойти до того, как действие выполнится, и что это действие никогда не должно выполняться, потому что я устанавливаю Response внутри атрибута.Почему атрибут не выполняется?

1 Ответ

1 голос
/ 15 мая 2019

Это можно сделать с помощью авторизации на основе политик.

Идея, по сути, заключается в том, что у вас есть требование, которое должно быть выполнено (действительный сертификат), обработчик для требования (как проверить сертификат) и политика, которая обеспечивает соблюдение этого требования и применяется во время авторизации.

Если ваш код достаточно прост, вы можете просто указать Func<AuthorizationHandlerContext, bool> для политики, которая применяется для оценки. Вот как настроить политику (в Startup.cs, ConfigureServices()):

services.AddAuthorization(options =>
{
    options.AddPolicy("ValidateCertificate", policy =>
       policy.RequireAssertion(context => 
       {
           var filterContext = (AuthorizationFilterContext)context.Resource;
           var Response = filterContext.HttpContext.Response;
           var message = Encoding.UTF8.GetBytes("Invalid certificate");
           Response.OnStarting(async () =>
           {
               filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
               await Response.Body.WriteAsync(message, 0, message.Length);
           });                       
           return false;
       }));
});

Это будет делать то, что вы хотите.

Теперь, если вы хотите пойти по более структурированному маршруту, вы можете реализовать каждый фрагмент:

Сначала создайте ваше требование (больше похоже на маркер для справки):

public class ValidCertificateRequirement : IAuthorizationRequirement
{

}

Затем настройте политику, которую нужно применить (Startup.cs, ConfigureServices()):

services.AddAuthorization(options => 
{
    options.AddPolicy("ValidateCertificate", policy => 
    {
        policy.Requirements.Add(new ValidCertificateRequirement());
    });
});

Теперь вам нужно создать обработчик требований:

public class ValidCertificateHandler : AuthorizationHandler<ValidCertificateRequirement>
{
    public ValidCertificateHandler()
    {
    }

    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ValidCertificateRequirement requirement)
    {
        var filterContext = (AuthorizationFilterContext)context.Resource;
        var Response = filterContext.HttpContext.Response;
        var message = Encoding.UTF8.GetBytes("Invalid certificate");
        Response.OnStarting(async () =>
        {
            filterContext.HttpContext.Response.StatusCode = (int)HttpStatusCode.Forbidden;
            await Response.Body.WriteAsync(message, 0, message.Length);
        });
        context.Fail();
        return Task.CompletedTask;
    }
}

Обработчик должен быть зарегистрирован при запуске (в ConfigureServices()):

//Register handler
services.AddSingleton<IAuthorizationHandler, ValidCertificateHandler>();

Наконец, для любого из подходов (утверждение или реализация) примените атрибут Authorize к своим действиям, указывая политику для применения:

[Authorize(Policy = "ValidateCertificate")]
public HttpResponseMessage TestAuth()
{
    return new HttpResponseMessage(HttpStatusCode.OK)
    {
        ReasonPhrase = "In Test method without any authorization."
    };
}

Подробнее об этом можно прочитать здесь:

Авторизация на основе политик в ASP.NET Core

...