断点未在AuthorizationFilterAttribute中命中

时间:2019-05-15 18:14:54

标签: c# authentication attributes asp.net-web-api2 asp.net-core-2.2

我具有此属性:

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 Web应用程序。显然,这只是用于路由,但我认为值得一提。

我已经在属性代码的第一行设置了一个断点,但是没有遇到问题。我相信它应该在动作执行之前被击中,并且该动作永远不会执行,因为我在属性内设置了Response。为什么不执行该属性?

1 个答案:

答案 0 :(得分:1)

这可以使用基于策略的授权来完成。

从本质上讲,这个想法是您有一个需要满足的要求(有效证书),该要求的处理程序(如何验证证书)以及强制执行此要求并在授权期间应用的策略。

如果您的代码足够简单,则只需向用于评估的策略提供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."
    };
}

您可以在此处了解更多信息:

Policy-based authorization in ASP.NET Core