Asp.net mvc 4 验证具有SPA体系结构的OrgeryToken
我正在尝试设置热毛巾水疗应用程序的注册和登录。我已经基于创建了SimpleMembershipFilters和ValidateHttpAntiForgeryTokenAttribute 你是如何得到这份工作的Asp.net mvc 4 验证具有SPA体系结构的OrgeryToken,asp.net-mvc-4,knockout.js,single-page-application,durandal,hottowel,Asp.net Mvc 4,Knockout.js,Single Page Application,Durandal,Hottowel,我正在尝试设置热毛巾水疗应用程序的注册和登录。我已经基于创建了SimpleMembershipFilters和ValidateHttpAntiForgeryTokenAttribute 你是如何得到这份工作的 @Html.AntiForgeryToken() 在Durandal SPA模式下工作的代码 目前我有一个register.html <section> <h2 data-bind="text: title"></h2> <l
@Html.AntiForgeryToken()
在Durandal SPA模式下工作的代码
目前我有一个register.html
<section>
<h2 data-bind="text: title"></h2>
<label>Firstname:</label><input data-bind="value: firstName" type="text" />
<label>Lastname:</label><input data-bind="value: lastName" type="text" />
<label>Email:</label><input data-bind="value: emailAddress" type="text" />
<label>Company:</label><input data-bind="value: company" type="text" />
<br />
<label>Password:</label><input data-bind="value: password1" type="password" />
<label>Re-Enter Password:</label><input data-bind="value: password2" type="password" />
<input type="button" value="Register" data-bind="click: registerUser" class="btn" />
</section>
在$ajax调用中,如何传递AntiForgeryToken?还有,如何创建令牌?在jsvar中获取令牌的值
var antiForgeryToken = $('input[name="__RequestVerificationToken"]').val();
然后只需在.ajax调用的函数中添加到ajax文章标题
beforeSend: function (xhr, settings) {
if (settings.data != "") {
settings.data += '&';
}
settings.data += '__RequestVerificationToken=' + encodeURIComponent(antiForgeryToken);
}
我将阅读如何使用javascript使用反伪造令牌。这篇文章是为WebApi编写的,但是如果您愿意,它可以很容易地应用于MVC控制器
简单的回答是这样的:
在cshtml视图中:
<script>
@functions{
public string TokenHeaderValue()
{
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
return cookieToken + ":" + formToken;
}
}
$.ajax("api/values", {
type: "post",
contentType: "application/json",
data: { }, // JSON data goes here
dataType: "json",
headers: {
'RequestVerificationToken': '@TokenHeaderValue()'
}
});
</script>
@功能{
公共字符串TokenHeaderValue()
{
字符串cookieToken,formToken;
antifforgery.GetTokens(null,out-cookieToken,out-formToken);
返回cookieToken+“:”+formToken;
}
}
$.ajax(“api/值”{
类型:“post”,
contentType:“应用程序/json”,
data:{},//JSON数据在这里
数据类型:“json”,
标题:{
“RequestVerificationToken”:“@TokenHeaderValue()”
}
});
然后,在asp.net控制器中,您需要验证令牌,如下所示:
void ValidateRequestHeader(HttpRequestMessage request)
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
void ValidateRequestHeader(HttpRequestMessage请求)
{
字符串cookieToken=“”;
字符串formToken=“”;
IEnumerable标记头;
if(request.Headers.TryGetValues(“RequestVerificationToken”,out-tokenHeaders))
{
string[]tokens=tokenHeaders.First().Split(“:”);
if(tokens.Length==2)
{
cookieToken=tokens[0]。Trim();
formToken=tokens[1].Trim();
}
}
防伪。验证(cookieToken,formToken);
}
您希望在标头中传递它的原因是,如果您在ajax调用中,在请求的querystring或body内部,将其作为参数数据参数传递。那么你就很难在所有不同的场景中获得防伪标识。因为您必须反序列化主体,然后找到令牌。在标题中,它非常一致并且易于检索
**编辑光线 下面是一个动作过滤器的示例,您可以使用它为web api方法添加属性,以验证是否提供了antiforgerytoken
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Helpers;
using System.Web.Http.Filters;
using System.Net.Http;
using System.Net;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
using System.Threading;
namespace PAWS.Web.Classes.Filters
{
public class ValidateJsonAntiForgeryTokenAttribute : FilterAttribute, IAuthorizationFilter
{
public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
if (actionContext == null)
{
throw new ArgumentNullException("HttpActionContext");
}
if (actionContext.Request.Method != HttpMethod.Get)
{
return ValidateAntiForgeryToken(actionContext, cancellationToken, continuation);
}
return continuation();
}
private Task<HttpResponseMessage> FromResult(HttpResponseMessage result)
{
var source = new TaskCompletionSource<HttpResponseMessage>();
source.SetResult(result);
return source.Task;
}
private Task<HttpResponseMessage> ValidateAntiForgeryToken(HttpActionContext actionContext, CancellationToken cancellationToken, Func<Task<HttpResponseMessage>> continuation)
{
try
{
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (actionContext.Request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
catch (System.Web.Mvc.HttpAntiForgeryException ex)
{
actionContext.Response = new HttpResponseMessage
{
StatusCode = HttpStatusCode.Forbidden,
RequestMessage = actionContext.ControllerContext.Request
};
return FromResult(actionContext.Response);
}
return continuation();
}
}
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
使用System.Web;
使用System.Web.Helpers;
使用System.Web.Http.Filters;
使用System.Net.Http;
Net系统;
使用System.Threading.Tasks;
使用System.Web.Http.Controller;
使用系统线程;
命名空间PAWS.Web.Classes.Filters
{
公共类ValidateJsonAntiForgeryTokenAttribute:FilterAttribute,IAAuthorizationFilter
{
公共任务ExecuteAuthorizationFilterAsync(HttpActionContext actionContext、CancellationToken CancellationToken、Func continuation)
{
if(actionContext==null)
{
抛出新ArgumentNullException(“HttpActionContext”);
}
if(actionContext.Request.Method!=HttpMethod.Get)
{
返回ValidateAntiForgeryToken(actionContext、cancellationToken、continuation);
}
返回continuation();
}
来自结果的私有任务(HttpResponseMessage结果)
{
var source=new TaskCompletionSource();
source.SetResult(结果);
返回源任务;
}
专用任务ValidateAntiForgeryToken(HttpActionContext actionContext、CancellationToken CancellationToken、Func continuation)
{
尝试
{
字符串cookieToken=“”;
字符串formToken=“”;
IEnumerable标记头;
if(actionContext.Request.Headers.TryGetValues(“RequestVerificationToken”,out-tokenHeaders))
{
string[]tokens=tokenHeaders.First().Split(“:”);
if(tokens.Length==2)
{
cookieToken=tokens[0]。Trim();
formToken=tokens[1].Trim();
}
}
防伪。验证(cookieToken,formToken);
}
捕获(System.Web.Mvc.HttpAntiforyException ex)
{
actionContext.Response=新的HttpResponseMessage
{
StatusCode=HttpStatusCode.禁止,
RequestMessage=actionContext.ControllerContext.Request
};
从结果返回(actionContext.Response);
}
返回continuation();
}
}
}
我对此有些纠结,因为对于我基于热毛巾模板的Durandal SPA应用程序,现有的答案似乎都不正确
我必须结合埃文·拉森和柯蒂斯克的回答,才能得到我认为应该得到的结果
在我的index.cshtml页面(Durandal支持cshtml和html)中,我在
标记上方添加了以下内容
@AntiForgery.GetHtml();
我按照Evan Larson的建议添加了一个自定义筛选器类,但是我必须修改它以支持单独查找cookie值,并使用u RequestVerificationToken作为名称,而不是RequestVerificationToken,因为这是Antifforgery.GetHtml()提供的
在应用程序中,我在my Global.asax下添加了
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
最后,对于我的ajax调用,我添加了curtisk输入查找的派生,以便在登录请求的情况下向ajax请求添加一个头
var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();
return Q.when($.ajax({
url: '/breeze/account/login',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(data),
headers: {
"__RequestVerificationToken": formForgeryToken
}
})).fail(handleError);
这导致我的所有post请求都需要一个基于cookie和由创建的隐藏表单验证令牌的验证令牌
public static void RegisterHttpFilters(HttpFilterCollection filters)
{
filters.Add(new ValidateJsonAntiForgeryTokenAttribute());
}
FilterConfig.RegisterHttpFilters(GlobalConfiguration.Configuration.Filters);
var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();
return Q.when($.ajax({
url: '/breeze/account/login',
type: 'POST',
contentType: 'application/json',
dataType: 'json',
data: JSON.stringify(data),
headers: {
"__RequestVerificationToken": formForgeryToken
}
})).fail(handleError);
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Mvc.Filters;
namespace SydHeller.Filters
{
public class ValidateJSONAntiForgeryHeader : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
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));
}
string serverToken = filterContext.HttpContext.Request.Cookies.Get(KEY_NAME).Value;
if (serverToken == null)
{
throw new HttpAntiForgeryException(string.Format("Cookies does not contain {0}", KEY_NAME));
}
System.Web.Helpers.AntiForgery.Validate(serverToken, clientToken);
}
private const string KEY_NAME = "__RequestVerificationToken";
}
}
var formForgeryToken = $('input[name="__RequestVerificationToken"]').val();
$.ajax({
type: "POST",
url: serviceURL,
contentType: "application/json; charset=utf-8",
dataType: "json",
data: requestData,
headers: {
"__RequestVerificationToken": formForgeryToken
},
success: crimeDataSuccessFunc,
error: crimeDataErrorFunc
});