为什么在添加全局授权筛选器时调用两次授权处理程序? [英] why Authorization Handler invoked two time when added a global authorization filter?
本文介绍了为什么在添加全局授权筛选器时调用两次授权处理程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!
问题描述
我在ASP.NET核心MVC 3.1中使用了基于策略的授权,我对Read有一个名为ReadAuthorizationRequirements的授权要求,我还有一个全局IPAllowweAuthorizationRequirements,它检查用户的IP并检查是否允许此IP继承上下文。
问题是,当我在第一次Invoke中添加两次调用的全局授权筛选器读取需求时,其资源为Microsoft.AspNetCore.Routing.RouteEndpoint在第二次Invoke中其资源为Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.AuthorizationFilterContextSealed 这会阻止上下文成功授权。我的Startup.cs如下:
services.AddAuthorization(options =>
{
options.FallbackPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
});
services.AddControllersWithViews(options =>
{
options.Filters.Add(new AuthorizeFilter(policy: Constants.Authorization.IpAllowed));
options.Filters.Add(typeof(Filters.RequestLoggingAttribute));
});
ReadAuthorizationHandler.cs
public class ReadAuthorizationHandler : AuthorizationHandler<ReadAuthorizationRequirement>
{
private readonly IApplicationRouteService _applicationRouteService;
public ReadAuthorizationHandler(IApplicationRouteService applicationRouteService)
{
_applicationRouteService = applicationRouteService;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, ReadAuthorizationRequirement requirement)
{
var roles = AuthorizationHanderHelper.FindRole(_applicationRouteService, context, requirement);
if (roles.Any(role => role.Read == true))
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
IpAllen weAuthorizationHandler.cs
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IpAllowedAuthorizationRequirement requirement)
{
if (context.Resource is Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext mvcContext)
{
var userIps = ((ClaimsIdentity)context.User.Identity).Claims
.Where(c => c.Type == Constants.Authorization.ClaimTypes.IpAddress)
.Select(c => c.Value).ToList();
var currentIp = mvcContext.HttpContext.Connection.RemoteIpAddress;
var bytes = currentIp.GetAddressBytes();
var badIp = true;
foreach (var address in userIps)
{
if (IPAddress.TryParse(address, out IPAddress testIp))
{
if (testIp.GetAddressBytes().SequenceEqual(bytes))
{
badIp = false;
break;
}
}
}
if (!badIp)
{
context.Succeed(requirement);
}
else
{
var routeData = mvcContext.RouteData;
var action = routeData.Values["action"] as string;
var controller = routeData.Values["controller"] as string;
var area = routeData.DataTokens["area"] as string;
if (string.IsNullOrEmpty(area) && controller == "Account" && action == "AccessDenied")
{
mvcContext.ModelState.TryAddModelError("", $"IP izni verilmemiştir! (IP: {currentIp})");
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
}
return Task.CompletedTask;
}
这是要在IpAllowed处理程序上读取的调用的图片:
1-第一个调用发生在读授权处理程序中,并且上下文为端点(此调用成功):
在读授权处理程序中发生了2秒的调用,上下文是MVC的AuthorizationFilterContext,这次失败。在第二个调用中,IpAllowed处于挂起的要求中。
推荐答案
这里提到 Setting Global Authorization policies using defaultpolicy and the fallback policy in aspnet core 3
和here
我对ASP.NET MVC核心使用了旧式全局授权筛选器,这在ASP.NET核心2.2中是可以的,但在3.0+中使用终结点路由时它不能像预期的那样工作。
所以我更改了代码,如下所示: Start.cs:
从配置服务中删除了回退策略,因为我添加了IpAllowed策略作为全局要求,如下所示。 从配置服务方法的选项中删除了全局授权筛选器,并在app.useEndpoint的配置方法中添加了需要授权,如下所示: app.UseEndpoints(endpoints =>
{
endpoints.MapDefaultControllerRoute().RequireAuthorization(Constants.Authorization.IpAllowed);
});
IpAllen weAuthorizationHandler.cs
更新处理程序如下:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, IpAllowedAuthorizationRequirement requirement)
{
if (context.Resource is Microsoft.AspNetCore.Routing.RouteEndpoint endpoint)
{
var userIps = ((ClaimsIdentity)context.User.Identity).Claims
.Where(c => c.Type == Constants.Authorization.ClaimTypes.IpAddress)
.Select(c => c.Value).ToList();
var currentIp = _contextAccessor?.HttpContext.Connection.RemoteIpAddress;
if(currentIp == null)
{
context.Fail();
return Task.CompletedTask;
}
var bytes = currentIp.GetAddressBytes();
var badIp = true;
foreach (var address in userIps)
{
if (IPAddress.TryParse(address, out IPAddress testIp))
{
if (testIp.GetAddressBytes().SequenceEqual(bytes))
{
badIp = false;
break;
}
}
}
if (!badIp)
{
context.Succeed(requirement);
}
else
{
context.Fail();
}
}
return Task.CompletedTask;
}
这篇关于为什么在添加全局授权筛选器时调用两次授权处理程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文