c# - 使用 AspNet Core MVC 在 Ajax 请求中验证 AntiForgeryToken

标签 c# ajax asp.net-core-mvc dnx antiforgerytoken

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

我最初的想法是继承ValidateAntiForgeryTokenAttribute ,但是查看源代码,我需要返回我自己的授权过滤器实现,以让它查看 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>();
    }
}

因此,我制作了自己的 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 注入(inject)之后,替换 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 的新实现。 ,在哪里或如何使用依赖注入(inject)注册它以使用它 - 并且仅用于我将接受 Ajax 请求的操作?

最佳答案

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

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

AJAX 调用类似于以下内容:

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

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

然后,只需在您的操作中使用 native 属性 [ValidadeAntiForgeryToken]

关于c# - 使用 AspNet Core MVC 在 Ajax 请求中验证 AntiForgeryToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36628666/

相关文章:

c# - 如何以编程方式获取当前的跟踪开关?

c# - 使用c#在一个单元格中使用多种格式

webclient - 在 ASP.NET 5 中使用 WebClient

asp.net - 为什么将 ReactJS 与 ASP.NET CORE MVC 结合使用?

c# - 如何在 .NET 中手动将错误推送到 NewRelic

php - 模式搜索的 Ajax 回调问题

javascript - 使用 JavaScript 从 Html 字符串获取文本

php - 通过 ajax post 将 div Html 和 Css 保存在数据库中。

asp.net-core-mvc - 覆盖生成的复选框名称(通过 asp-for)

c# - 在 C# 中按下按钮时数字不断减少