每个API调用都必须具有唯一的AddAntiForgery令牌吗?

时间:2018-06-12 21:26:17

标签: javascript asp.net asp.net-mvc antiforgerytoken

我知道在FORM中使用调用Html.AddAntiForgeryToken会起作用。 但是对于没有Form的情况,应该在何处/如何获得防伪签名?

每个令牌都必须是唯一的吗?或者,网络应用程序可以在整个会话期间使用相同的防伪令牌吗?

1 个答案:

答案 0 :(得分:0)

AntiForgeryToken值属于页面,然后属于form。如果您在@Html.AntiForgeryToken()的同一页面上放置多个表单(当然不是嵌套!!!),那么所有值都是相同的。重新加载页面时(GETPOST之后),值会发生变化 在内部,Web Server设置HttpOnly Cookie(AntiForgeryConfig类中定义的名称),并将收到的值与该cookie值进行比较。
如果您从该页面进行API(AJAX)调用怎么办?当然,你可以根据自己的意愿拨打多个电话 如果页面上没有form怎么办?您需要添加 form。这样的事情。

@{
    var attr = new Dictionary<string, object>();
    attr.Add("id", "anti-forgery"); //sic!
}
@using (Html.BeginForm("", "fake-form", FormMethod.Post, attr))
{
    @Html.AntiForgeryToken()
}

然后立即设置所有您的AJAX电话。

<script>
    'use strict';
    $(document).ready(function () {
        $.ajaxSetup({
            dataType: 'json',
            method: 'POST',
            contentType: 'application/json',
            headers: antiForgery({}) //put antiforgerytoken into ajax request header
        });
        function antiForgery(data) {
            data.__RequestVerificationToken = $('#anti-forgery input[name=__RequestVerificationToken]').val();
            return data;
        }

    });

</script>

在服务器端,您需要使用并验证请求。以下方法使用自定义属性类。

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext filterContext)
    {
        if (filterContext == null)
        {
            throw new ArgumentNullException("filterContext");
        }

        var httpContext = filterContext.HttpContext;
        var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName];
        AntiForgery.Validate(cookie != null ? cookie.Value : null, httpContext.Request.Headers["__RequestVerificationToken"]);
    }
}

现在你只用这个属性装饰你的控制器方法。

[HttpPost]
[ValidateJsonAntiForgeryToken] //this one
public async Task<JsonResult> ProcessRq(MyModel model)
{
    //do work
}

如果您创建纯API(RESTfull)服务,那么也有类似的方法。客户端应用程序首先必须请求并接收某种身份验证令牌,并将其添加到所有下一个请求中(在会话期间)。