MVC 4 - AntiForgeryValidationToken仅为第一次请求创建cookie

本文关键字:第一次 请求 创建 cookie AntiForgeryValidationToken MVC | 更新日期: 2023-09-27 17:49:28

好了,这是我们昨天处理的一个奇怪的案例。当我们的站点被加载时,对这个表单的第一个请求按预期工作。防伪验证通过,没有错误,一切正常。但是,在第一次初始成功使用之后,其他浏览器请求将停止生成防伪造令牌的cookie部分。所有后续的发布尝试都将返回一个500,表示cookie不存在。查看浏览器资源确认cookie不存在。我假设这是某种配置问题,因为在我们的测试和开发环境中工作得很好,但是一旦我们转移到我们的登台环境,问题就出现了,我已经没有办法了。

我有一个这样的控制器动作:

[HttpPost]
[ValidateAntiForgeryToken()]
public bool someFunction(string someParameter) {
    // Do things
    return success;
}

在我们的页面上,我有一个像这样的from设置

<form id="someForm">
    @Html.AntiForgeryToken()
    <input type="text" name="someField" />
</form>

它是这样连接的:

$("#someForm").On("submit", function(e) {
e.PreventDefault();
var url = "path/to/action";
var someFieldVal = $(this).Find('[name="someField"]').val();
var token = $(this).Find('[name="__RequestValidationToken"]');
var data = { '__RequestVerificationToken': token, 'someParameter': someFieldval };
$.ajax({
     type: "POST",
     url: url,
     data: data,
     success: function (response) {//do stuff}
     });
}

MVC 4 - AntiForgeryValidationToken仅为第一次请求创建cookie

对于ajax帖子,您可以将令牌放在标题中而不是数据中。

$.ajax(
    {
        type: "POST",
        url: url,
        headers: { "__RequestVerificationToken": token },
        data: data,
        success: function (response) {//do stuff}
|;

编辑

我忘记了另一半。

你说第二个浏览器帖子没有防伪cookie。如果发生这种情况,那将是一个问题。但是,从您的代码示例中,似乎您的ajax帖子不包括cookie而不是浏览器请求。

这个cookie是一个httponly cookie。这意味着(除其他事项外)javascript无法访问它。如果使用ajax发布表单,则会包含cookie。但是,您的发帖数据。所以它不包括防伪造cookie,因为ajax不允许读取cookie并将cookie包含在帖子中。

有些人会在每个页面上放一个只用于ajax帖子的表单。但是,我更喜欢发布数据而不是表单。我发布的第二部分是创建一个授权属性。该属性在报头中查找令牌,然后对其进行验证。

下面是创建我使用的authorize属性的类。

[AttributeUsage(AttributeTargets.Class)]
public sealed class ValidateAntiForgeryTokenOnAllPosts : 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);
            }
        }
    }
}

然后您只需将属性添加到每个您想要验证防伪令牌的控制器。

[ValidateAntiForgeryTokenOnAllPosts]
public class SomeController : Controller
{   }

我想这是我第一次学会如何做到这一点的网站:http://richiban.uk/2013/02/06/validating-net-mvc-4-anti-forgery-tokens-in-ajax-requests/