如何解决自定义授权过滤器在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 举报,一经查实,本站将立刻删除。