AuthorizeAttribute过滤器上的应用程序令牌错误

时间:2018-03-13 11:25:34

标签: ajax asp.net-mvc authentication filter antiforgerytoken

在我的AJAX POST上,我发送AntiForgeryToken以验证我的控制器操作,为此我使用AuthorizeAttribute过滤器来验证它。

它在本地机器上工作得很好。但是,在服务器上,它会验证从同一服务器/域上的另一个站点在浏览器上注册的第一个AntiForgeryToken。

我的AuthorizeAttribute过滤器:

public void OnAuthorization(AuthorizationContext filterContext)
{
    if(filterContext == null)
        throw new HttpAntiForgeryException("filterContext is null");

    if (filterContext.RequestContext == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext is null");

    if (filterContext.RequestContext.HttpContext == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext is null");

    if (filterContext.RequestContext.HttpContext.Request == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request is null");

    if (filterContext.RequestContext.HttpContext.Request.Headers == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request.Headers is null");

    if (filterContext.RequestContext.HttpContext.Request.Cookies == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request.Cookies is null");

    string KEY_NAME = "__RequestVerificationToken";

    string clientToken = filterContext.RequestContext.HttpContext.Request.Headers.Get(KEY_NAME);
    if (clientToken == null)
    {
        throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
    }

    var key = filterContext.HttpContext.Request.Cookies.AllKeys.FirstOrDefault(m => m == KEY_NAME);
    if (string.IsNullOrEmpty(key))
        key = filterContext.HttpContext.Request.Cookies.AllKeys.FirstOrDefault(m => m != null && m.Contains(KEY_NAME + "_"));
    if (string.IsNullOrEmpty(key))
        key = filterContext.HttpContext.Request.Cookies.AllKeys.FirstOrDefault(m => m != null && m.Contains(KEY_NAME));

    var serverToken = filterContext.HttpContext.Request.Cookies.Get(key ?? KEY_NAME);
    if (serverToken == null)
    {
        throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
    }

    System.Web.Helpers.AntiForgery.Validate(serverToken.Value, clientToken);
}

我的AJAX请求:

$.ajax({
    type: !methodType ? "POST" : methodType,
    url: methodName,
    data: methodType == "get" || methodType == "GET" ? parameters : typeof parameters !== "undefined" && parameters != null ? JSON.stringify(parameters) : null,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    headers: {
        "__RequestVerificationToken": token
    },
    processdata: true,
    success: succeededHandler,
    async: isAsync,
    crossDomain: false,
    error: errorHandler
})
    .done(function (data) {
    if (doneHandler)
        doneHandler();
})
.always(function (xhr) {
    closeLoadingDialog();

    try {
        if (xhr.status == 401 || (xhr.getResponseHeader("X-Responded-JSON") != null
            && JSON.parse(xhr.getResponseHeader("X-Responded-JSON")).status == "401")) {
            (location ? location : window.location).reload();
            return;
        }
    }
    catch (er) { }
});

我已经发现问题可能是我使用serverToken搜索key FirstOrDefault()的方式。这是在浏览器上注册的所有cookie,而不仅仅是应用程序cookie。

但我怎样才能只查看应用程序cookie ?如何在AuthorizeAttribute过滤器上解决此问题?

1 个答案:

答案 0 :(得分:0)

经过多次搜索和突破后,我发现这个link显示了一种类似的方法来验证AntiForgeryToken。但是在这里他们使用AntiForgeryConfig.CookieName属性来获取应用程序cookie。

他们说:

  

CookieName是类的静态属性   System.Web.Helpers.AntiForgeryConfig。

     

你可以在这里看到更多:   http://msdn.microsoft.com/en-us/library/system.web.helpers.antiforgeryconfig.cookiename(v=vs.111).aspx

所以我将代码更改为:

public void OnAuthorization(AuthorizationContext filterContext)
{
    string KEY_NAME = "__RequestVerificationToken";

    if (filterContext == null)
        throw new HttpAntiForgeryException("filterContext is null");

    if (filterContext.RequestContext == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext is null");

    if (filterContext.RequestContext.HttpContext == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext is null");

    if (filterContext.RequestContext.HttpContext.Request == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request is null");

    if (filterContext.RequestContext.HttpContext.Request.Headers == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request.Headers is null");

    if (filterContext.RequestContext.HttpContext.Request.Cookies == null)
        throw new HttpAntiForgeryException("filterContext.RequestContext.HttpContext.Request.Cookies is null");

    var request = filterContext.HttpContext.Request;


    //  Ajax POSTs and normal form posts have to be treated differently when it comes to validating the AntiForgeryToken
    if (request.IsAjaxRequest())
    {
        string clientToken = request.Headers.Get(KEY_NAME);
        if (clientToken == null)
        {
            throw new HttpAntiForgeryException(string.Format("Header does not contain {0}", KEY_NAME));
        }
        var serverToken = request.Cookies[AntiForgeryConfig.CookieName];
        var cookieValue = serverToken != null ? serverToken.Value : KEY_NAME;

        AntiForgery.Validate(cookieValue, clientToken);
    }
    else
    {
        new ValidateAntiForgeryTokenAttribute().OnAuthorization(filterContext);
    }
}

现在工作得很好!