使用WebForm中的MVC HtmlHelper

Pet*_*r J 18 asp.net-mvc webforms html-helper

我正在向混合WebForms/MVC站点添加一些UI功能.在这种情况下,我将一些AJAX UI功能添加到WebForms页面(通过jQuery),数据来自MVC JsonResult.一切都在100%工作,但有一个例外:

我想实现AntiForgeryToken的XSRF保护.我已经将它与我的纯MVC应用程序上的ValidateAntiForgeryToken属性结合使用,但是想知道如何在WebForms中实现Html.AntiForgeryToken()方法. 以下是使用UrlHelper的示例.

我正确地将ViewContext/RequestContext"模拟"起来有些麻烦.我应该如何在WebForms页面中使用HtmlHelpers?

编辑:我想从我的WebForms页面检索AntiForgeryToken,而不是从MVC JsonResult.

pva*_*ten 20

我知道这是一个老问题,但今天我遇到了这个问题并且认为我会分享.我正在使用MVC4并且有一个webform控件(.ascx),它在MVC(通过RenderPartial)和WebForms之间共享.在那个控件中,我需要一个防伪令牌.幸运的是,现在你可以在webforms中使用一个帮助器,就像这样简单:

<%= AntiForgery.GetHtml() %>
Run Code Online (Sandbox Code Playgroud)

这会像你在MVC中那样呈现你的防伪标记.

这是它的MS链接.


Kei*_*ith 6

关键方法是在MVC源代码中: GetAntiForgeryTokenAndSetCookie

这将创建一个名为内部密封类的实例AntiForgeryData.

该实例被序列化为cookie"__RequestVerificationToken_"+应用程序路径的base 64编码版本.

相同的实例AntiForgeryData被序列化为隐藏输入.

独特的部分AntiForgeryData是有一个RNGCryptoServiceProvider.GetBytes()

所有这些都可能在WebForms页面中被欺骗,唯一的混乱是隐藏密封类的序列化.不幸的是,密钥方法(GetAntiForgeryTokenAndSetCookie)依赖于ViewContext.HttpContext.Request获取cookie,而WebForm则需要使用HttpContext.Current.Request.


更新

没有太多的测试和很多代码,但我想我已经通过一点反思解决了这个问题.在我使用反射的地方,我留下了上面注释的等效行:

using System;
using System.Reflection;
using System.Web;
using System.Web.Mvc;

/// <summary>Utility to provide MVC anti forgery tokens in WebForms pages</summary>
public class WebFormAntiForgery
{
    /// <summary>Create an anti forgery token in a WebForms page</summary>
    /// <returns>The HTML input and sets the cookie</returns>
    public static string AntiForgeryToken()
    {
        string formValue = GetAntiForgeryTokenAndSetCookie();

        // string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);
        var mvcAssembly = typeof(HtmlHelper).Assembly;
        var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData");
        string fieldName = Convert.ToString(afdType.InvokeMember(
            "GetAntiForgeryTokenName",
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
            null,
            null,
            new object[] { null }));

        TagBuilder builder = new TagBuilder("input");
        builder.Attributes["type"] = "hidden";
        builder.Attributes["name"] = fieldName;
        builder.Attributes["value"] = formValue;
        return builder.ToString(TagRenderMode.SelfClosing);
    }

    static string GetAntiForgeryTokenAndSetCookie()
    {
        var mvcAssembly = typeof(HtmlHelper).Assembly;
        var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData");

        // new AntiForgeryDataSerializer();
        var serializerType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryDataSerializer");
        var serializerCtor = serializerType.GetConstructor(new Type[0]);
        object serializer = serializerCtor.Invoke(new object[0]); 

        // string cookieName = AntiForgeryData.GetAntiForgeryTokenName(HttpContext.Current.Request.ApplicationPath);
        string cookieName = Convert.ToString(afdType.InvokeMember(
            "GetAntiForgeryTokenName",
            BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod,
            null,
            null,
            new object[] { HttpContext.Current.Request.ApplicationPath }));

        // AntiForgeryData cookieToken;
        object cookieToken;
        HttpCookie cookie = HttpContext.Current.Request.Cookies[cookieName];
        if (cookie != null)
        {
            // cookieToken = Serializer.Deserialize(cookie.Value);
            cookieToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookie.Value });
        }
        else
        {
            // cookieToken = AntiForgeryData.NewToken();
            cookieToken = afdType.InvokeMember(
                "NewToken",
                BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,
                null,
                null,
                new object[0]);

            // string cookieValue = Serializer.Serialize(cookieToken);
            string cookieValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookieToken }));

            var newCookie = new HttpCookie(cookieName, cookieValue) { HttpOnly = true };

            HttpContext.Current.Response.Cookies.Set(newCookie);
        }

        // AntiForgeryData formToken = new AntiForgeryData(cookieToken)
        // {
        //     CreationDate = DateTime.Now,
        //     Salt = salt
        // };
        var ctor = afdType.GetConstructor(new Type[] { afdType });
        object formToken = ctor.Invoke(new object[] { cookieToken });

        afdType.InvokeMember("CreationDate", BindingFlags.SetProperty, null, formToken, new object[] { DateTime.Now });
        afdType.InvokeMember("Salt", BindingFlags.SetProperty, null, formToken, new object[] { null });

        // string formValue = Serializer.Serialize(formToken);
        string formValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { formToken }));
        return formValue;
    }
}
Run Code Online (Sandbox Code Playgroud)

用法类似于MVC:

WebFormAntiForgery.AntiForgeryToken()
Run Code Online (Sandbox Code Playgroud)

它创建与MVC方法相同的cookie和相同的HTML.

我没有使用salt和domain方法,但是它们很容易添加.