asp.net-mvc-4 - 使用 SPA 架构验证AntiForgeryToken

标签 asp.net-mvc-4 knockout.js single-page-application durandal hottowel

我正在尝试设置 Hot Towel SPA申请的注册和登录。我已经根据 asp.net single page application template 创建了 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>

register.js:

define(['services/logger'], function (logger) {
    var vm = {
        activate: activate,
        title: 'Register',
        firstName: ko.observable(),
        lastName: ko.observable(),
        emailAddress: ko.observable(),
        company: ko.observable(),
        password1: ko.observable(),
        password2: ko.observable(),
        registerUser: function () {
            var d = {
                'FirstName': vm.firstName,
                'LastName': vm.lastName,
                'EmailAddress': vm.emailAddress,
                'Company': vm.company,
                'Password': vm.password1,
                'ConfirmPassword': vm.password2
            };
            $.ajax({
                url: 'Account/JsonRegister',
                type: "POST",
                data: d ,
                success: function (result) {
                },
                error: function (result) {
                }
            });
        },
    };


    return vm;

    //#region Internal Methods
    function activate() {
        logger.log('Login Screen Activated', null, 'login', true);
        return true;
    }
    //#endregion
});

在 $ajax 调用中如何传递 AntiForgeryToken?另外我如何创建 token ?

最佳答案

我会读this article关于如何使用 javascript 使用防伪 token 。本文是针对 WebApi 编写的,但如果您愿意,它可以轻松应用于 MVC Controller 。

简短的回答是这样的: 在你的 cshtml View 中:

<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>

然后在您的 asp.net Controller 中,您需要像这样验证 token :

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

您想要在 header 中传递它的原因是,如果您在 ajax 调用中将其作为参数数据参数传递,则位于请求的查询字符串或正文中。那么您将更难获得适用于所有不同场景的防伪 token 。因为您必须反序列化主体然后找到 token 。在标题中,它非常一致且易于检索。

<小时/>

**编辑光线

以下是操作过滤器的示例,您可以使用它来指定 Web API 方法的属性,以验证是否提供了防伪 token 。

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

关于asp.net-mvc-4 - 使用 SPA 架构验证AntiForgeryToken,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15416264/

相关文章:

c# - 子网格更新时刷新父 Kendo MVC 网格

javascript - jQuery:如何遍历/迭代对象列表

javascript - Knockout JS : ko. applyBindings 不是函数

knockout.js - 单击行中的复选框在行 knockout 绑定(bind)上触发事件绑定(bind)

angularjs - 将 ngRoute 与 Express 后端一起使用

angular - 我将 ng2-metadata 与我的 Angular 版本 4 应用程序一起使用,谷歌似乎只显示默认标题和描述

reactjs - 如何在单个 ASP.NET Core 站点上托管多个 React SPA 应用程序?

asp.net - MVC 4 应用程序服务层中的单元测试

Jquery dd/MM/yyyy 日期格式验证

knockout.js - 您如何在 knockout 模板中控制台登录