C# AntiForgeryToken 属性在 mvc 应用程序中导致 StackOverflowException

C# AntiForgeryToken attribute causes StackOverflowException in mvc application

我已经创建了一个防伪属性 class 来装饰我的 GenericBaseController class:

[AttributeUsage(AttributeTargets.Class)]
public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        var request = filterContext.HttpContext.Request;

        //  Only validate POSTs
        if (request.HttpMethod == WebRequestMethods.Http.Post)
        {
            //  Ajax POSTs and normal form posts have to be treated differently when it comes
            //  to validating the AntiForgeryToken
            if (request.IsAjaxRequest())
            {
                var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                var cookieValue = antiForgeryCookie != null
                    ? antiForgeryCookie.Value
                    : null;

                AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
            }
            else
            {
                new ValidateAntiForgeryTokenAttribute()
                    .OnAuthorization(filterContext);
            }
        }
    }
}

(参考 link http://richiban.uk/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/

一旦应用程序中的正常 POST 调用完成(不是 ajax),我总是会收到 WhosebugException。 没有 ValidateAntiForgeryTokenAttribute 的应用程序工作正常。 如果我在这个 class 中调试代码,在 post 请求之后,流程继续通过行

new ValidateAntiForgeryTokenAttribute()
    .OnAuthorization(filterContext);

无限。 linked 文章中的人保证此实现有效,所以我想知道为什么我会遇到这个问题。 当请求不是 ajax 时,它真的应该创建一个新的 ValidateAntiForgeryTokenAttribute 吗?

归结为问题,你的代码是:

public class ValidateAntiForgeryTokenAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        if ( evaluateCondition() )
        {}
        else
        {
            new ValidateAntiForgeryTokenAttribute()
                .OnAuthorization(filterContext);
        }
    }
}

问题

您的调用在 else 块中递归:

  • 您调用方法的 class 是 ValidateAntiForgeryTokenAttribute

  • 在您的 else 区块中您有

    new ValidateAntiForgeryTokenAttribute()
        .OnAuthorization(filterContext);
    

    其中,鉴于调用方法是

    public override void OnAuthorization(AuthorizationContext filterContext)
    

    意味着您将在 ValidateAntiForgeryTokenAttribute.

  • 的新实例上继续调用 OnAuthorization(即相同的方法)

解决方案

在您发布的示例中,情况略有不同 - class 的名称是 ValidateAntiForgeryTokenOnAllPosts 而您的名称是 ValidateAntiForgeryTokenAttribute,因此调用不是递归的,因为方法没有用相同的参数调用自己。

您有三个选项 - 我不确定哪个最适合您的情况(我在考虑第一个):

  • 将您的属性名称更改为 ValidateAntiForgeryTokenOnAllPosts 以匹配 the example you posted 中的名称。

  • 通过将块更改为 say

    明确说明您想要 System.Web.Mvc.ValidateAntiForgeryTokenAttribute
    new System.Web.Mvc.ValidateAntiForgeryTokenAttribute()
        .OnAuthorization(filterContext);
    
  • 因为你覆盖了ValidateAntiForgeryTokenAttribute,你可以调用基本方法,即

    else
    {
        base.OnAuthorization(filterContext);
    }