微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

自定义授权过滤器在ASP.NET Core 3中不起作用

如何解决自定义授权过滤器在ASP.NET Core 3中不起作用

我正在使用自定义授权属性筛选器将AzureAD的身份验证(并最终授权)添加到ASP.NET Core 3.1应用程序中。下面的代码实现了IAuthorizationFilter的{​​{1}}方法,在该方法中,当用户的身份验证过期时,我将用户重定向OnAuthorization页面

当使用SignIn的控制器动作被击中时,我希望无论身份验证cookie是否已过期,都将立即击中属性[CustomAuthorizationFilter]方法

不会发生这种期望,相反,如果未对用户进行身份验证并单击了控制器操作,则会自动向Microsoft重新验证用户并创建有效的cookie,然后才单击OnAuthorization方法,击败我认为的OnAuthorization方法的目的。

我已经做了很多研究来了解这种行为,但是我显然缺少了一些东西。我发现的最有用的信息是在Microsoft docs中:

从ASP.NET Core 3.0开始,MVC不会为以下对象添加AllowAnonymousFilters 在控制器上发现的[AllowAnonymous]属性和 行动方法。此更改针对本地的 AuthorizeAttribute,但这是一个重大变化 IAsyncAuthorizationFilter和IAuthorizationFilter实现。

因此,看来OnAuthorization的实现可能在3.0+中被破坏,我不知道如何解决

此行为正常还是我的实现不正确?

如果正常,为什么在运行IAuthorizationFilter方法之前重新进行身份验证?

如果不正确,如何正确实施?

CustomAuthorizationFilter.cs

OnAuthorization

使用的IsAjaxRequest()扩展名:

public class CustomAuthorizationFilter : AuthorizeAttribute,IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationFilterContext context)
    {
        string signInPageUrl = "/UserAccess/SignIn";

        if (context.HttpContext.User.Identity.IsAuthenticated == false)
        {
            if (context.HttpContext.Request.IsAjaxRequest())
            {
                context.HttpContext.Response.StatusCode = 401;
                JsonResult jsonResult = new JsonResult(new { redirectUrl = signInPageUrl });
                context.Result = jsonResult;
            }
            else
            {
                context.Result = new RedirectResult(signInPageUrl);
            }
        }
    }
}

Startup.cs中的AzureAD身份验证实现

//Needed code equivalent of Request.IsAjaxRequest().
//Found this solution for ASP.NET Core: https://stackoverflow.com/questions/29282190/where-is-request-isajaxrequest-in-asp-net-core-mvc
//This is the one used in ASP.NET MVC 5: https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Mvc/AjaxRequestExtensions.cs
public static class AjaxRequestExtensions
{
    public static bool IsAjaxRequest(this HttpRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        if (request.Headers != null)
        {
            return (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }

        return false;
    }
}

解决方法

我希望找到一种创建AuthorizeAttribute过滤器的方法来解决此问题,但是由于时间限制,我选择了常规操作过滤器。它可以与AJAX调用一起使用,并且可以将用户重定向到适当的页面(如果这些页面未经授权或未经验证):

AjaxAuthorize操作过滤器:

//custom AjaxAuthorize filter inherits from ActionFilterAttribute because there is an issue with 
//a inheriting from AuthorizeAttribute.
//post about issue: 
//https://stackoverflow.com/questions/64017688/custom-authorization-filter-not-working-in-asp-net-core-3

//The statuses for AJAX calls are handled in InitializeGlobalAjaxEventHandlers JS function.

//While this filter was made to be used on actions that are called by AJAX,it can also handle
//authorization not called through AJAX.
//When using this filter always place it above any others as it is not guaranteed to run first.

//usage: [AjaxAuthorize(new[] {"RoleName","AnotherRoleName"})]
public class AjaxAuthorize : ActionFilterAttribute
{
    public string[] Roles { get; set; }

    public AjaxAuthorize(params string[] roles)
    {
        Roles = roles;
    }

    public override void OnActionExecuting(ActionExecutingContext context)
    {
        string signInPageUrl = "/UserAccess/SignIn";
        string notAuthorizedUrl = "/UserAccess/NotAuthorized";

        if (context.HttpContext.User.Identity.IsAuthenticated)
        {
            if (Roles.Length > 0)
            {
                bool userHasRole = false;
                foreach (var item in Roles)
                {
                    if (context.HttpContext.User.IsInRole(item))
                    {
                        userHasRole = true;
                    }
                }
                if (userHasRole == false)
                {
                    if (context.HttpContext.Request.IsAjaxRequest())
                    {
                        context.HttpContext.Response.StatusCode = 401;
                        JsonResult jsonResult = new JsonResult(new { redirectUrl = notAuthorizedUrl });
                        context.Result = jsonResult;
                    }

                    else
                    {
                        context.Result = new RedirectResult(notAuthorizedUrl);
                    }
                }
            }

        }
        else
        {
            if (context.HttpContext.Request.IsAjaxRequest())
            {
                context.HttpContext.Response.StatusCode = 403;
                JsonResult jsonResult = new JsonResult(new { redirectUrl = signInPageUrl });
                context.Result = jsonResult;
            }
            else
            {
                context.Result = new RedirectResult(signInPageUrl);
            }
        }
    }
}

使用的IsAjaxRequest()扩展名(重新发布以获取完整答案):

//Needed code equivalent of Request.IsAjaxRequest().
//Found this solution for ASP.NET Core: https://stackoverflow.com/questions/29282190/where-is-request-isajaxrequest-in-asp-net-core-mvc
//This is the one used in ASP.NET MVC 5: https://github.com/aspnet/AspNetWebStack/blob/master/src/System.Web.Mvc/AjaxRequestExtensions.cs
public static class AjaxRequestExtensions
{
    public static bool IsAjaxRequest(this HttpRequest request)
    {
        if (request == null)
        {
            throw new ArgumentNullException("request");
        }

        if (request.Headers != null)
        {
            return (request.Headers["X-Requested-With"] == "XMLHttpRequest");
        }

        return false;
    }
}

JavaScript ajax全局错误处理程序:

//global settings for the AJAX error handler. All AJAX error events are routed to this function.
function InitializeGlobalAjaxEventHandlers() {
    $(document).ajaxError(function (event,xhr,ajaxSettings,thrownError) {
        //these statuses are set in the [AjaxAuthorize] action filter
        if (xhr.status == 401 || xhr.status == 403) {
            var response = $.parseJSON(xhr.responseText);
            window.location.replace(response.redirectUrl);
        } else {
           RedirectUserToErrorPage();
        }     
    });
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。