实现Angular / MVC / WebAPI友好的AntiForgery令牌

时间:2014-09-26 16:16:31

标签: c# angularjs asp.net-mvc-4 asp.net-web-api

作为我即将开展的项目研究的一部分,我正在开发一个执行反XCRF验证的测试平台应用程序。

在开始我的研究时,我找到了this article, detailing how to do very nearly exactly what I am trying to do.

然而,我遇到了障碍。我实现了以下几段代码,但每次运行我的测试操作时,删除都具有[AntiForgeryValidate]属性,我会一直得到HttpAntiForgeryException;更重要的是,在请求标头中,没有__RequestVerificationToken,尽管从我的代码中可以看出,我正在专门添加它。

请求验证令牌指令:

app.directive('requestVerificationToken', [
    '$http',
    function ($http) {
        return function (scope, element, attrs) {
            $http.defaults.headers.common['__RequestVerificationToken'] = attrs.requestVerificationToken || "no request verification token";
        };
    }
]);

AntiForgeryExtension.cs:

public static class AntiForgeryExtension
{
    public static string RequestVerificationToken(this HtmlHelper helper)
    {
        // This name is dictated by the name of our validation token directive.
        // See App/Common/requestVerificationTokenDir.js.
        return String.Format("request-verification-token={0}", GetTokenHeaderValue());
    }

    private static string GetTokenHeaderValue()
    {
        string cookieToken;
        string formToken;

        System.Web.Helpers.AntiForgery.GetTokens(null, out cookieToken, out formToken);
        return cookieToken + ":" + formToken;
    }
}

AntiForgeryValidate.cs:

public class AntiForgeryValidate : ActionFilterAttribute
{
    public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)
    {
        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();
            }
        }
        System.Web.Helpers.AntiForgery.Validate(cookieToken, formToken);

        base.OnActionExecuting(actionContext);
    }
}

TestController.cs:

public class HomeController : ApiController
{
    //api/home/DeleteThingy
    [HttpGet]
    [AntiForgeryValidate]
    public HttpResponseMessage DeleteThingy(int thingyId)
    {
        // ...Magic!
        return Request.CreateResponse(HttpStatusCode.OK);
    }
}

...最后, Index.cshtml

<div class='container'>
    <input type='hidden' @Html.RequestVerificationToken() />
    <div data-ng-view></div>
</div>

问题:我做错了什么,导致__RequestVerificationToken没有出现在我点击前端删除按钮时传回服务器的标题中?

2 个答案:

答案 0 :(得分:1)

您可能不希望指令添加CSRF令牌,您需要HTTP拦截器。例如,

app.factory('httpInterceptor', function () {
    return {
        request: function (config) {
            // csrf token for non get calls
            if (config.method != 'GET') {
                config.headers.__RequestVerificationToken =
                    jQuery('input[name="__RequestVerificationToken"]').val();
            }
            return config;
        },
    };
})

这可确保所有非HTTP GET都具有CSRF令牌,这是您从安全角度所需的。要添加拦截器,只需按下这样的数组:

app.config(['$httpProvider', function ($httpProvider) {
    $httpProvider.interceptors.push('httpInterceptor');
}])

答案 1 :(得分:1)

简短的回答:我的代码没有任何问题,除了我没有在我的捆绑中包含所有JavaScript引用!这是一个ID-10T错误。