Asp.net mvc 4 验证具有SPA体系结构的OrgeryToken

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

我正在尝试设置热毛巾水疗应用程序的注册和登录。我已经基于创建了SimpleMembershipFilters和ValidateHttpAntiForgeryTokenAttribute

你是如何得到这份工作的

 @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
});