Asp.net core 创建从AuthorizationFilter继承的自定义AuthorizationFilter时未调用OnAuthorizationAsync

Asp.net core 创建从AuthorizationFilter继承的自定义AuthorizationFilter时未调用OnAuthorizationAsync,asp.net-core,asp.net-core-webapi,asp.net-core-3.1,Asp.net Core,Asp.net Core Webapi,Asp.net Core 3.1,我创建了一个自定义授权筛选器,如下所示: public class BearerTokenAuthorizeFilter : AuthorizeFilter { public override async Task OnAuthorizationAsync(AuthorizationFilterContext context) { await base.OnAuthorizationAsync(context); if (conte

我创建了一个自定义授权筛选器,如下所示:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
我正在按如下方式注册此筛选器:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});

我在控制器上添加了
Authorize
属性。每当我向端点发送未经授权的请求时,我的自定义筛选器从未被调用,我也不知道为什么?我的目标是,如果请求未经授权向消费者提供比状态代码多一点的信息,则返回问题详细信息。为什么没有调用我的筛选器?

尝试实施
iaauthorizationfilter
IAsyncAuthorizationFilter
而不是
authorizationfilter
。这对我有用。我还注意到,
GetFilter(…)
方法直接在
AuthorizationApplicationModelProvider
中返回
AuthorizeFilter
实例,当filter类实现
AuthorizeFilter
时。但是当filter实现
iaauthorizationfilter
IAsyncAuthorizationFilter
时,我认为这是ASP.NET中的问题,请尝试实现
iaauthorizationfilter
IAsyncAuthorizationFilter
而不是
authorizationfilter
。这对我有用。我还注意到,
GetFilter(…)
方法直接在
AuthorizationApplicationModelProvider
中返回
AuthorizeFilter
实例,当filter类实现
AuthorizeFilter
时。但是当filter实现
IAuthorizationFilter
IAsyncAuthorizationFilter
这个方法没有被调用时,我认为这是ASP.NET中的问题

我最终实现了我自己的
IControllerModelConvention
类,它看起来像这样:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
公共类BearTokenAuthorizeConvention:IControllerModelConvention
{
私人授权政策(u政策),;
公共承运人授权公约(授权政策)
{
_政策=政策;
}        
公共无效应用(控制器模型控制器)
{
if(controller.Filters.OfType().FirstOrDefault()==null)
{
//默认策略仅在控制器中没有授权筛选器时使用
controller.Filters.Add(新的BealerTokenAuthorizeFilter(_策略));
}
}
}
这将在每个控制器上执行一次。然后我注册了这样一个公约:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
//配置应用程序筛选器和约定
配置(选项=>
{
AuthorizationPolicy defaultPolicy=新建AuthorizationOptions().defaultPolicy;
添加(新BealerTokenAuthorizeConvention(defaultPolicy));
});

此时,我拥有的每个控制器都将被这个自定义过滤器标记,它将调用
AuthorizeFilter
的基本实现。我之所以想从
AuthorizeFilter
派生,是因为我想调用
authorized
的默认实现,然后自己处理失败的响应。我认为我可以完成这项功能,但不知何故仍然只能使用
Authorize
属性。这似乎是不可能的。除非是我遗漏了什么?

我最终实现了自己的
IControllerModelConvention
类,该类如下所示:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
公共类BearTokenAuthorizeConvention:IControllerModelConvention
{
私人授权政策(u政策),;
公共承运人授权公约(授权政策)
{
_政策=政策;
}        
公共无效应用(控制器模型控制器)
{
if(controller.Filters.OfType().FirstOrDefault()==null)
{
//默认策略仅在控制器中没有授权筛选器时使用
controller.Filters.Add(新的BealerTokenAuthorizeFilter(_策略));
}
}
}
这将在每个控制器上执行一次。然后我注册了这样一个公约:

public class BearerTokenAuthorizeFilter : AuthorizeFilter
{        
    public override async Task OnAuthorizationAsync(AuthorizationFilterContext context)
    {
        await base.OnAuthorizationAsync(context);
        if (context.Result is ChallengeResult)
        {
            // Then return a problem detail
            ObjectResult result = new ObjectResult(new ProblemDetails
            {
                Type = ProblemDetailsTypes.Unauthorized,
                Title = ReasonPhrases.GetReasonPhrase(StatusCodes.Status401Unauthorized),
                Status = StatusCodes.Status401Unauthorized,
                Detail = ProblemDetailsDescriptions.Unauthorized
            });
            result.ContentTypes.Add(new MediaTypeHeaderValue(new Microsoft.Extensions.Primitives.StringSegment("application/problem+json")));
            
            context.Result = result;
            await context.HttpContext.ChallengeAsync();
        }
        else if (context.Result is ForbidResult)
        {
            context.Result = new StatusCodeResult(StatusCodes.Status403Forbidden);
            await context.HttpContext.ForbidAsync();
        }
    }
}
services.AddMvcCore(options =>
{
    options.Filters.Add<BearerTokenAuthorizeFilter>();
});
public class BearerTokenAuthorizeConvention : IControllerModelConvention
{
    private AuthorizationPolicy _policy;

    public BearerTokenAuthorizeConvention(AuthorizationPolicy policy)
    {
        _policy = policy;
    }        
    public void Apply(ControllerModel controller)
    {
        if (controller.Filters.OfType<BearerTokenAuthorizeFilter>().FirstOrDefault() == null)
        {
            //default policy only used when there is no authorize filter in the controller
            controller.Filters.Add(new BearerTokenAuthorizeFilter(_policy));
        }
    }
}
// Configure application filters and conventions
services.Configure<MvcOptions>(options =>
{
    AuthorizationPolicy defaultPolicy = new AuthorizationOptions().DefaultPolicy;
    options.Conventions.Add(new BearerTokenAuthorizeConvention(defaultPolicy));
});
//配置应用程序筛选器和约定
配置(选项=>
{
AuthorizationPolicy defaultPolicy=新建AuthorizationOptions().defaultPolicy;
添加(新BealerTokenAuthorizeConvention(defaultPolicy));
});

此时,我拥有的每个控制器都将被这个自定义过滤器标记,它将调用
AuthorizeFilter
的基本实现。我之所以想从
AuthorizeFilter
派生,是因为我想调用
authorized
的默认实现,然后自己处理失败的响应。我认为我可以完成这项功能,但不知何故仍然只能使用
Authorize
属性。这似乎是不可能的。除非它是一个I'm missing something?

请检查Startup.cs文件中的Configure方法,确保已添加UseAuthentication和UseAuthentication中间件,代码如下:
app.UseAuthentication();app.UseAuthorization()
。请检查Startup.cs文件中的Configure方法,确保已添加UseAuthentication和UseAuthentication中间件,代码如下:
app.UseAuthentication();app.UseAuthorization()。我想问题是,我用
Authorize
属性标记了控制器,而不是用
BearerTokenAuthorize
标记了控制器。所以我的自定义过滤器从未被调用。我想问题是,我用
Authorize
属性标记了控制器,而不是用
BearerTokenAuthorize
标记了控制器。所以我的自定义过滤器从未被调用。