我知道在FORM中使用调用Html.AddAntiForgeryToken会起作用。 但是对于没有Form的情况,应该在何处/如何获得防伪签名?
每个令牌都必须是唯一的吗?或者,网络应用程序可以在整个会话期间使用相同的防伪令牌吗?
答案 0 :(得分:0)
AntiForgeryToken值属于页面,然后属于form
。如果您在@Html.AntiForgeryToken()
的同一页面上放置多个表单(当然不是嵌套!!!),那么所有值都是相同的。重新加载页面时(GET
或POST
之后),值会发生变化
在内部,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)服务,那么也有类似的方法。客户端应用程序首先必须请求并接收某种身份验证令牌,并将其添加到所有下一个请求中(在会话期间)。