使用 SPA 架构验证AntiForgeryToken [英] ValidateAntiForgeryToken with SPA architecture

查看:25
本文介绍了使用 SPA 架构验证AntiForgeryToken的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试为 Hot Towel SPA 申请设置注册和登录.我已经基于 asp.net 单页应用程序模板创建了 SimpleMembershipFilters 和 ValidateHttpAntiForgeryTokenAttribute.

I am trying to set Register and Login for Hot Towel SPA applicantion. I have created SimpleMembershipFilters and ValidateHttpAntiForgeryTokenAttribute based on the asp.net single page application template.

你如何获得

 @Html.AntiForgeryToken()

在 Durandal SPA 模式中工作的代码.

code to work in the Durandal SPA pattern.

目前我有一个 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?另外我如何创建令牌?

In the $ajax call how do I pass the AntiForgeryToken? Also how do I create the token as well?

推荐答案

我会阅读 这篇文章 关于如何使用 javascript 使用防伪令牌.这篇文章是为 WebApi 编写的,但如果您愿意,它可以很容易地应用于 MVC 控制器.

I would read this article on how to use antiforgery tokens using javascript. The article is written for WebApi but it can easily applied to an MVC controller if you want to.

简短的回答是这样的:在您的 cshtml 视图中:

The short answer is something like this: Inside your 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 控制器中,您需要像这样验证令牌:

Then inside your asp.net controller you need to validate the token like so:

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

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

The reason you want to pass it in the headers is because if you pass it as a parameter data parameter in your ajax call, inside the querystring or body, of the request. Then it will be harder for you to get the antiforgery token for all your different scenarios. Because you will have to deserialize the body and then find the token. In the headers its pretty consistent and easy to retrieve.

**编辑光线

这是一个操作过滤器的示例,您可以使用它来对 Web api 方法进行属性验证,以验证是否提供了防伪令牌.

Here is an example of an action filter which you can use to attribute web api methods to validate if a antiforgerytoken is provided.

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

这篇关于使用 SPA 架构验证AntiForgeryToken的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆