Значение AntiForgeryToken относится скорее к странице, чем к form
.Если вы разместите несколько форм (конечно, не вложенных !!!) на одной странице с @Html.AntiForgeryToken()
, тогда все значения будут одинаковыми.Когда страница перезагружается (после GET
или POST
), значение изменяется.
Внутренне веб-сервер устанавливает 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), то естьпохожий подход.Сначала клиентское приложение должно запросить и получить какой-нибудь токен аутентификации и добавить его ко всем следующим запросам (во время сеанса).