【问题标题】:Why is AntiForgeryToken validation failing when using AngularJS in ASP.NET MVC app?为什么在 ASP.NET MVC 应用程序中使用 AngularJS 时,AntiForgeryToken 验证失败?
【发布时间】:2016-08-24 19:11:09
【问题描述】:

在 ASP.NET MVC 应用程序中使用 AngularJS $http 服务时,我在传递正确的 AntiForgertyToken 时遇到了一些问题。

我尝试了以下方法:

  1. 使用 httpInterceptor 设置 HTTP 请求标头

    app.factory('httpInterceptorService', function ($q) {
        return {
            'request': function (config) {
                blockUI();
                config.headers['If-Modified-Since'] = 'Mon, 26 Jul 1997 05:00:00 GMT'; // Disables IE AJAX request caching
                config.headers['Cache-Control'] = 'no-cache';
                config.headers['Pragma'] = 'no-cache';
                config.headers['X-Requested-With'] = 'XMLHttpRequest';
                config.headers['__RequestVerificationToken'] = $('[name=__RequestVerificationToken]').val();
                return config;
            },
    
  2. 通过工厂服务设置 HTTP 请求标头

    app.factory('networkService', function ($http) {
        return {
            postDataAsAjax: function (url, params) {
                debugger;
                return $http({
                    method: 'POST',
                    url: url,
                    data: params,
                    headers: {
                        '__RequestVerificationToken': $('[name=__RequestVerificationToken]').val(),
                        'X-Requested-With': 'XMLHttpRequest'
                    }
                }).then(function (result) {
    

这两种方法都抛出 AntiForgeryTokenException。

还有其他方法可以实现吗?

编辑(添加 HTTP 请求信息)

POST /WebApplication1/Home/Index HTTP/1.1
Host: localhost
Connection: keep-alive
Content-Length: 799
Cache-Control: no-cache
Pragma: no-cache
Origin: http://localhost
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/50.0.2661.94 Safari/537.36
Content-Type: application/json;charset=UTF-8
Accept: application/json, text/plain, */*
X-Requested-With: XMLHttpRequest
If-Modified-Since: Mon, 26 Jul 1997 05:00:00 GMT
__RequestVerificationToken: CKCARSoIug5mHnHmUT4ciSmf3pCk1YJkcwq3czo5snfEwTVPBUYLQj7z7w3KKDu001RYk7zuMZ1LEwwWB1tNpZR0agxJK1DjqjMDnQNewLKGCmExANXIJ-Du7lc0LEFw0
Referer: http://localhost/SSP-Working_SourceCode/
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.8
Cookie: __ngDebug=true; ASP.NET_SessionId=4kcpxz1oj0042ndw4aotx0jl; __RequestVerificationToken_L1NTUC1Xb3JraW5nX1NvdXJjZUNvZGU1=Q8FOz7jJHQHdes02AJvRGglFU_pcz5eqcnZY3QXg37z9k1LMYiPWq-kKbXlYCbAfK0IgLpCtpBax6w-rB1J_NBi7KzGyCuwLCHjKNREjMhQ1; .ASPXFORMSAUTH=CC35114F38FD17866FAF38A1FDC525263A0858EFECFB03AEEED7E9AF7FAA2995262A426D4AA50EB87C47969C3C191BC9B3D31BC67A831C099F286AD3013348B14659632BC54425E3D81C19CB382E175B2DA3755DDFE46D7A79810FB79EBE832D616A299C93CFDA2105576B922C6A1D111A23BB6F9594532C310A15AF2162785A

编辑(添加自定义防伪令牌属性)

public class GlobalAntiForgeryTokenAttribute : IAuthorizationFilter
{
    public void OnAuthorization(AuthorizationContext authorizationContext)
    {
        var request = authorizationContext.HttpContext.Request;

        if (request.HttpMethod.ToUpper() != "POST")
        {
            return;
        }

        if (authorizationContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
            authorizationContext.ActionDescriptor.ControllerDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true))
        {
            return;
        }

        if (request.IsAjaxRequest())
        {
            var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];
            var cookieValue = antiForgeryCookie != null ? antiForgeryCookie.Value : null;
            AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"]);
        }
        else
        {
            new ValidateAntiForgeryTokenAttribute().OnAuthorization(authorizationContext);
        }
    }
}

编辑(添加 HTTP 响应)

System.Web.Mvc.HttpAntiForgeryException: 所需的防伪表单字段__RequestVerificationToken 不存在。

【问题讨论】:

  • 你能发布 HTTP 请求的样子吗?
  • @JohnMc 用 HTTP 请求信息更新了帖子。
  • 谢谢。您能否确认此处引发了异常:AntiForgery.Validate(cookieValue, request.Headers["__RequestVerificationToken"])?如果没有,在哪里?
  • @JohnMc 是的,这就是它被抛出的地方。

标签: angularjs asp.net-mvc csrf-protection antiforgerytoken asp.net-mvc-5.1


【解决方案1】:

问题是验证令牌是表单数据的一部分,但您在标题中提供了它。

This post 告诉您如何构建一个属性过滤器来验证标题。

这是我的:

[AttributeUsage(AttributeTargets.Class)]
    public class ValidateAntiForgeryTokenOnAjax : AuthorizeAttribute
    {
        public override void OnAuthorization(AuthorizationContext filterContext)
        {
            var request = filterContext.HttpContext.Request;

            //  Only validate POSTs
            if (request.HttpMethod == WebRequestMethods.Http.Post)
            {
                //  Ajax POSTs and normal form posts have to be treated differently when it comes
                //  to validating the AntiForgeryToken
                if (request.IsAjaxRequest())
                {
                    var antiForgeryCookie = request.Cookies[AntiForgeryConfig.CookieName];

                    var cookieValue = antiForgeryCookie != null
                        ? antiForgeryCookie.Value
                        : null;

                    AntiForgery.Validate(cookieValue, request.Headers[AntiForgeryConfig.CookieName]);
                }
                else
                {
                    new ValidateAntiForgeryTokenAttribute()
                        .OnAuthorization(filterContext);
                }
            }
        }

然后我像这样配置角度:

var myApp = angular.module("myApp", ["ngRoute"])
    .run(function ($http) {
        $http.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest';
        $http.defaults.headers.post["__RequestVerificationToken"] = $("#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]").val();
    });

在我的主布局页面上,我声明了这个表单:

<form id="__AjaxAntiForgeryForm" action="#" method="post">@Html.AntiForgeryToken()</form>

【讨论】:

  • 感谢您的回复。我们有一个自定义属性,它通过标头验证 AJAX 请求。请查看更新后的帖子。
  • 这是我在这个问题上的分步方法。我正在使用 angularJS、jquery、ASP.NET MVC 5 stackoverflow.com/a/57781976/2508781
【解决方案2】:

对于那些面临类似问题的人来说,我们的应用程序的问题是之前的开发人员还在请求集发布到的 MVC 控制器操作上定义了默认的“ValidateAntiForgeryToken”属性。

一旦我们从控制器操作中移除 [ValidationAntiForgeryToken],它就开始工作了。

我们有一个自定义的防伪令牌属性来检查标头中的令牌,但是 MVC 属性的默认实现只检查请求正文,这导致了失败。

【讨论】:

    猜你喜欢
    • 2018-06-10
    • 2018-12-28
    • 2013-02-05
    • 2011-01-02
    • 1970-01-01
    • 2012-06-17
    • 2020-06-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多