使用AspNet Core MVC在Ajax请求中验证AntiForgeryToken [英] ValidateAntiForgeryToken in Ajax request with AspNet Core MVC

查看:142
本文介绍了使用AspNet Core MVC在Ajax请求中验证AntiForgeryToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在尝试重新创建ValidateAntiForgeryToken的Ajax版本-许多博客文章介绍了如何针对MVC的早期版本执行此操作,但是对于最新的MVC 6,没有任何相关的代码.不过,我要遵循的核心原则是让验证程序查看Cookie和__RequestVerificationToken的标题,而不是将Cookie与表单值进行比较.我使用的是MVC 6.0.0-rc1-final,dnx451框架,并且所有Microsoft.Extensions库都是1.0.0-rc1-final.

I have been trying to recreate an Ajax version of the ValidateAntiForgeryToken - there are many blog posts on how to do this for previous versions of MVC, but with the latest MVC 6, none of the code is relevant. The core principle that I am going after, though, is to have the validation look at the Cookie and the Header for the __RequestVerificationToken, instead of comparing the Cookie to a form value. I am using MVC 6.0.0-rc1-final, dnx451 framework, and all of the Microsoft.Extensions libraries are 1.0.0-rc1-final.

我最初的想法是仅继承

My initial thought was to just inherit ValidateAntiForgeryTokenAttribute, but looking at the source code, I would need to return my own implementation of an an Authorization Filter to get it to look at the header.

[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>();
    }
}

这样,然后我制作了自己的验证AntiforgeryTokenAuthorizationFilter

As such, I then made my own version of 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;
    }
}

但是,我找不到包含

However, I cannot find the proper Nuget package and namespace that contains IAntiforgeryPolicy. While I found the interface on GitHub - what package do I find it in?

我的下一个尝试是改为注射IAntiforgery之后,并替换

My next attempt was to instead go after the IAntiforgery injection, and replace the DefaultAntiforgery with my own 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>();
    }
}

在停滞之前,我已经了解到了这一点,因为CreateLogger<T>()ILoggerFactory上没有通用方法. DefaultAntiforgery的源代码具有Microsoft.Extensions.Options,但是我在任何Nuget包中都找不到该命名空间. Microsoft.Extensions.OptionsModel存在,但这只是引入了IOptions<out TOptions>界面.

I got this far before I stalled out because there is no generic method on ILoggerFactory for CreateLogger<T>(). The source code for DefaultAntiforgery has Microsoft.Extensions.Options, but I cannot find that namespace in any Nuget package. Microsoft.Extensions.OptionsModel exists, but that just brings in the IOptions<out TOptions> interface.

要继续进行所有这些操作,一旦我使授权过滤器可以工作,或者我获得了IAntiforgery的新实现,我应该在何处或如何向其注入依赖项以使用它-且仅用于我将接受Ajax请求的操作?

To follow all of this up, once I do get the Authorization Filter to work, or I get a new implementation of IAntiforgery, where or how do I register it with the dependency injection to use it - and only for the actions that I will be accepting Ajax requests?

推荐答案

我遇到了类似的问题.我不知道.NET是否会对此进行任何更改,但是当时,我在 Startup.cs 中的 ConfigureServices 方法中添加了以下几行,行services.AddMvc(),以验证通过Ajax发送的AntiForgeryToken:

I had similar issue. I don't know if any changes are coming regarding this in .NET but, at the time, I added the following lines to ConfigureServices method in Startup.cs, before the line services.AddMvc(), in order to validate the AntiForgeryToken sent via Ajax:

services.AddAntiforgery(options =>
{
    options.CookieName = "yourChosenCookieName"; 
    options.HeaderName = "RequestVerificationToken";
});

AJAX调用将类似于以下内容:

The AJAX call would be something like the following:

var token = $('input[type=hidden][name=__RequestVerificationToken]', document).val();

var request = $.ajax({
    data: { 'yourField': 'yourValue' },
    ...
    headers: { 'RequestVerificationToken': token }
});   

然后,只需在操作中使用本机属性 [ValidadeAntiForgeryToken] .

Then, just use the native attribute [ValidadeAntiForgeryToken] in your Actions.

这篇关于使用AspNet Core MVC在Ajax请求中验证AntiForgeryToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆