Использование MVC HtmlHelper из WebForm - PullRequest
18 голосов
/ 28 августа 2009

Я в процессе добавления некоторой функциональности пользовательского интерфейса на гибридный сайт WebForms / MVC. В этом случае я добавляю некоторые функции пользовательского интерфейса AJAX на страницу WebForms (через jQuery), и данные поступают из MVC JsonResult. Все работает на 100%, с одним исключением:

Я бы хотел реализовать XSRF-защиту AntiForgeryToken. Я использовал его в сочетании с атрибутом ValidateAntiForgeryToken в моих чистых приложениях MVC, но хотел бы знать, как реализовать метод Html.AntiForgeryToken () в WebForms. Вот пример использования UrlHelper .

У меня возникли проблемы с корректным макетом ViewContext / RequestContext. Как мне использовать HtmlHelpers на странице веб-форм?

Редактировать : Я пытаюсь получить AntiForgeryToken со своей страницы WebForms, а не из MVC JsonResult.

Ответы [ 4 ]

18 голосов
/ 01 мая 2013

Я знаю, что это старый вопрос, но я столкнулся с этим вопросом сегодня и думал, что поделюсь. Я работаю в MVC4 и имею элемент управления веб-формой (.ascx), который совместно используется как MVC (через RenderPartial), так и веб-формами. В этом контроле мне понадобился токен против подделки. К счастью, теперь есть помощник, который вы можете использовать в своих веб-формах, теперь он прост:

<%= AntiForgery.GetHtml() %>

При этом ваш токен защиты от подделки будет выглядеть так же, как в MVC.

Вот MS ссылка на него .

6 голосов
/ 31 марта 2010

Ключевой метод в исходном коде MVC: GetAntiForgeryTokenAndSetCookie

Это создает экземпляр внутреннего запечатанного класса с именем AntiForgeryData.

Экземпляр сериализуется в cookie-файл "__RequestVerificationToken_" + кодированная версия пути приложения в кодировке 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;
    }
}

Использование тогда аналогично MVC:

WebFormAntiForgery.AntiForgeryToken()

Создает тот же файл cookie и тот же HTML, что и методы MVC.

Я не беспокоился о методах соли и домена, но их было бы довольно легко добавить.

1 голос
/ 04 сентября 2009

По умолчанию в ASP.NET WebForms уже включены меры для проверки событий и состояния просмотра. Фил Хаак немного говорит об этом в связанном посте. Стратегии смягчения последствий XSRF обсуждаются здесь (Скотт Хансельман) и здесь (Dino Esposito)

0 голосов
/ 28 августа 2009

вы можете создать новый HtmlHelper в вашем контроллере, а затем вытащить оттуда анти-xrsf:

var htmlHelper = new HtmlHelper(
    new ViewContext(
        ControllerContext, 
        new WebFormView("omg"), 
        new ViewDataDictionary(), 
        new TempDataDictionary()), 
        new ViewPage());

var xsrf = htmlHeler.AntiForgeryToken;

myObject.XsrfToken = xsrf;

return JsonResult(myObject);
...