在我的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过滤器上解决此问题?
答案 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);
}
}
现在工作得很好!