动态地将@ Html.AntiForgeryToken()添加到所有表单

时间:2015-01-31 07:17:02

标签: asp.net-mvc asp.net-mvc-3 asp.net-mvc-4

是否有可能动态地将@Html.AntiForgeryToken()添加到MVC中的所有表单标记,而不是手动添加到所有页面?

2 个答案:

答案 0 :(得分:1)

您可以在母版页上创建另一个表单,以确保创建AntiForgery cookie(如果客户端浏览器中没有它),并且在其关联所需的DOM中存在隐藏字段。

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

然后使用jQuery或Javascript,您可以拦截所有表单提交,然后添加AntiForgeryToken值,然后访问如下:

$('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val()

有很多方法可以拦截表单提交,我没有时间编写完整的测试,因此您应该在使用之前测试下面的代码,因为它可能有错误。但是您可能希望为应该被拦截或挂钩到其ID的表单定义一个类。但是你的结构可能看起来像这样:

$("#formid").submit(function(e){
e.preventDefault(); //prevent submit
var self = this;

  $('<input />').attr('type', 'hidden')
      .attr('name', "__RequestVerificationToken")
      .attr('value', $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val())
      .appendTo('#formid');
self.submit();   })  });

当然,这个解决方案的问题在于客户端需要启用JavaScript,但在今天的日常生活中,这是一个合理的假设。另一种方法是创建自己的自定义HtmlHelper,而不是使用MVC附带的库存标准。但是这种JavaScript方法的另一个好处是可以为您的ajax帖子添加AntiForgery支持,因为您还可以将JavaScript函数添加到同一母版页:

 <script type="text/javascript">
    AddAntiForgeryToken = function (data) {
        data.__RequestVerificationToken = $('#__AjaxAntiForgeryForm input[name=__RequestVerificationToken]').val();
        return data;
    };
</script>

这意味着,为了执行Ajax帖子,您可以执行以下操作:

$.ajax({
        url: '/YourTargetUrl',
        cache: false,
        type: "POST",
        data: AddAntiForgeryToken({ field1: value1, ..... fieldx: valuex }),
        dataType: "json",
        success: function (response) {
        },
        error: function (xhr, status, error) {               
        } });

答案 1 :(得分:0)

您可以构建自己的Form HTML帮助程序重载,通过复制FormExtensions源代码中的内容并添加代码以生成防伪标记来自动执行此操作。

public static class FormExtensions
{
    public static MvcForm BeginFormWithAntiForgeryToken(this HtmlHelper htmlHelper, string actionName, string controllerName, object routeValues, FormMethod method, object htmlAttributes)
    {
        return BeginFormWithAntiForgeryToken(htmlHelper, actionName, controllerName, new RouteValueDictionary(routeValues), method, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
    }

    public static MvcForm BeginFormWithAntiForgeryToken(this HtmlHelper htmlHelper, string actionName, string controllerName, RouteValueDictionary routeValues, FormMethod method, IDictionary<string, object> htmlAttributes)
    {
        string formAction = UrlHelper.GenerateUrl(null /* routeName */, actionName, controllerName, routeValues, htmlHelper.RouteCollection, htmlHelper.ViewContext.RequestContext, true /* includeImplicitMvcValues */);
        return FormHelper(htmlHelper, formAction, method, htmlAttributes);
    }

    // TODO: Add additional overloads

    private static MvcForm FormHelper(this HtmlHelper htmlHelper, string formAction, FormMethod method, IDictionary<string, object> htmlAttributes)
    {
        TagBuilder tagBuilder = new TagBuilder("form");
        tagBuilder.MergeAttributes(htmlAttributes);
        // action is implicitly generated, so htmlAttributes take precedence.
        tagBuilder.MergeAttribute("action", formAction);
        // method is an explicit parameter, so it takes precedence over the htmlAttributes.
        tagBuilder.MergeAttribute("method", HtmlHelper.GetFormMethodString(method), true);

        bool traditionalJavascriptEnabled = htmlHelper.ViewContext.ClientValidationEnabled
                                            && !htmlHelper.ViewContext.UnobtrusiveJavaScriptEnabled;

        if (traditionalJavascriptEnabled)
        {
            // forms must have an ID for client validation
            tagBuilder.GenerateId(htmlHelper.ViewContext.FormIdGenerator());
        }

        htmlHelper.ViewContext.Writer.Write(tagBuilder.ToString(TagRenderMode.StartTag));

        // THIS WAS ADDED: Write the anti-forgery token
        htmlHelper.ViewContext.Writer.Write(System.Web.Helpers.AntiForgery.GetHtml().ToString());

        MvcForm theForm = new MvcForm(htmlHelper.ViewContext);

        if (traditionalJavascriptEnabled)
        {
            htmlHelper.ViewContext.FormContext.FormId = tagBuilder.Attributes["id"];
        }

        return theForm;
    }
}

然后,您只需在创建表单时调用HTML帮助程序。

@Html.BeginFormWithAntiForgeryToken("Edit", "User", new { id = 123 }, FormMethod.Post, null) {
    <!-- Add form elements here -->
}