【发布时间】:2016-08-06 08:03:24
【问题描述】:
我一直在尝试重新创建 ValidateAntiForgeryToken 的 Ajax 版本 - 有很多关于如何为以前版本的 MVC 执行此操作的博客文章,但对于最新的 MVC 6,没有任何代码是相关的。不过,我要遵循的核心原则是让验证查看__RequestVerificationToken 的 Cookie 和 Header,而不是将 Cookie 与表单值进行比较。我使用的是 MVC 6.0.0-rc1-final、dnx451 框架,所有 Microsoft.Extensions 库都是 1.0.0-rc1-final。
我最初的想法是只继承ValidateAntiForgeryTokenAttribute,但是查看源代码,我需要返回我自己的授权过滤器实现以使其查看标头。
[AttributeUsage(AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public class ValidateAjaxAntiForgeryTokenAttribute : Attribute, IFilterFactory, IFilterMetadata, IOrderedFilter
{
public int Order { get; set; }
public bool IsReusable => true;
public IFilterMetadata CreateInstance(IServiceProvider serviceProvider)
{
return serviceProvider.GetRequiredService<ValidateAjaxAntiforgeryTokenAuthorizationFilter>();
}
}
因此,我随后制作了自己的 ValidateAntiforgeryTokenAuthorizationFilter 版本
public class ValidateAjaxAntiforgeryTokenAuthorizationFilter : IAsyncAuthorizationFilter, IAntiforgeryPolicy
{
private readonly IAntiforgery _antiforgery;
private readonly ILogger _logger;
public ValidateAjaxAntiforgeryTokenAuthorizationFilter(IAntiforgery antiforgery, ILoggerFactory loggerFactory)
{
if (antiforgery == null)
{
throw new ArgumentNullException(nameof(antiforgery));
}
_antiforgery = antiforgery;
_logger = loggerFactory.CreateLogger<ValidateAjaxAntiforgeryTokenAuthorizationFilter>();
}
public async Task OnAuthorizationAsync(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
if (IsClosestAntiforgeryPolicy(context.Filters) && ShouldValidate(context))
{
try
{
await _antiforgery.ValidateRequestAsync(context.HttpContext);
}
catch (AjaxAntiforgeryValidationException exception)
{
_logger.LogInformation(1, string.Concat("Ajax Antiforgery token validation failed. ", exception.Message));
context.Result = new BadRequestResult();
}
}
}
protected virtual bool ShouldValidate(AuthorizationContext context)
{
if (context == null)
{
throw new ArgumentNullException(nameof(context));
}
return true;
}
private bool IsClosestAntiforgeryPolicy(IList<IFilterMetadata> filters)
{
// Determine if this instance is the 'effective' antiforgery policy.
for (var i = filters.Count - 1; i >= 0; i--)
{
var filter = filters[i];
if (filter is IAntiforgeryPolicy)
{
return object.ReferenceEquals(this, filter);
}
}
Debug.Fail("The current instance should be in the list of filters.");
return false;
}
}
但是,我找不到包含 IAntiforgeryPolicy 的正确 Nuget 包和命名空间。虽然我在 GitHub 上找到了接口 - 我在哪个包中找到它?
我的下一个尝试是在 IAntiforgery 注射后进行,并将 DefaultAntiforgery 替换为我自己的 AjaxAntiforgery。
public class AjaxAntiforgery : DefaultAntiforgery
{
private readonly AntiforgeryOptions _options;
private readonly IAntiforgeryTokenGenerator _tokenGenerator;
private readonly IAntiforgeryTokenSerializer _tokenSerializer;
private readonly IAntiforgeryTokenStore _tokenStore;
private readonly ILogger<AjaxAntiforgery> _logger;
public AjaxAntiforgery(
IOptions<AntiforgeryOptions> antiforgeryOptionsAccessor,
IAntiforgeryTokenGenerator tokenGenerator,
IAntiforgeryTokenSerializer tokenSerializer,
IAntiforgeryTokenStore tokenStore,
ILoggerFactory loggerFactory)
{
_options = antiforgeryOptionsAccessor.Value;
_tokenGenerator = tokenGenerator;
_tokenSerializer = tokenSerializer;
_tokenStore = tokenStore;
_logger = loggerFactory.CreateLogger<AjaxAntiforgery>();
}
}
因为ILoggerFactory 上没有针对CreateLogger<T>() 的通用方法,所以在我停滞不前之前我已经做到了这一点。 DefaultAntiforgery 的源代码有 Microsoft.Extensions.Options,但我在任何 Nuget 包中都找不到该命名空间。 Microsoft.Extensions.OptionsModel 存在,但只是引入了IOptions<out TOptions> 接口。
为了跟进所有这些,一旦我让授权过滤器工作,或者我获得了IAntiforgery 的新实现,我在哪里或如何将它注册到依赖注入以使用它 - 并且仅用于我将接受 Ajax 请求的操作?
【问题讨论】:
标签: c# ajax asp.net-core-mvc dnx antiforgerytoken