Исправление Asp.net Mvc2 AntiForgeryToken исключение - PullRequest
0 голосов
/ 28 сентября 2010

Некоторые предыстории моей проблемы:

Похоже, что в Mvc2 есть изменение / ошибка, касающаяся ValidateAntiForgeryTokenAttribute.

При обновлении с Mvc1 до Mvc2 пользователи с активным сеансом получат следующую ошибку при запросе страницы, используя ValidateAntiForgeryTokenAttribute:

Невозможно привести объект типа 'Система.Web.UI.Triplet 'для ввода' System.Object [] '.

Проблема задокументирована здесь .

После обновления до Mvc2 мыожидать, что мы будем серьезно затронуты этой проблемой.Я написал исправление, полученное из кода в комментариях (документировано ниже для потомков).На данный момент этот код вызывается путем создания подкласса Controller и AsyncController, переопределяющего метод Initialize для исправления проблемы.например,

public class FixedController:Controller
{
    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);
        this.FixAntiForgeryTokenMvc1ToMvc2(requestContext); //extension
    }
}

internal static class ControllerEx
{
    public static void FixAntiForgeryTokenMvc1ToMvc2(
        this Controller controller,
        RequestContext requestContext)
    {
        var cc = new ControllerContext(requestContext,
                                       controller);
        var antiForgeryAttribute = new ValidateAntiForgeryTokenAttribute();
        try
        {
            antiForgeryAttribute.OnAuthorization(new AuthorizationContext(cc));
        }
        catch (HttpAntiForgeryException forgeryException)
        {
            var castException = forgeryException.InnerException;
            if (castException != null
                && castException is InvalidCastException
                && castException.Message.StartsWith(
                       "Unable to cast object of type"
                       + " 'System.Web.UI.Triplet' to type"
                       + " 'System.Object[]'"))
            {
                var responseTokenCookieNames =
                    controller
                        .Response
                        .Cookies
                        .Cast<Cookie>()
                        .Select(c => c.Name)
                        .Where(n => n.Contains("RequestVerificationToken"));
                foreach (var s in responseTokenCookieNames)
                {
                    var cookie = controller.Response.Cookies[s];
                    if (cookie != null)
                    {
                        cookie.Value = "";
                    }
                }
                var requestTokenCookieNames =
                    controller
                        .Request
                        .Cookies
                        .Cast<String>()
                        .Where(n => n.Contains("RequestVerificationToken"))
                        .ToList();
                foreach (var c in requestTokenCookieNames)
                {
                    controller.Request.Cookies.Remove(c);
                }
            }
        }
    }
}

Стук, который возникает из-за этого, заключается в том, что я должен изменить все свои классы контроллеров для получения из моих новых исправленных подклассов контроллеров.Это кажется довольно навязчивым для кода, который намеревается объявить устаревшим примерно через месяц.

Итак, возвращаясь к моему вопросу, я хотел бы знать, есть ли менее навязчивые средства для исправления существующих классов, чтобы нижестоящие пользователикласса не должны быть изменены, возможно, с помощью отражения?

1 Ответ

1 голос
/ 28 сентября 2010

Spender,

вместо того, чтобы кодировать каждый контроллер, используйте basecontroller и наследуйте от него в соответствии с:

public abstract class BaseController : Controller
{
    protected override void Initialize(RequestContext requestContext)
    {
        base.Initialize(requestContext);
        FixAntiForgeryTokenMvc1ToMvc2(this, requestContext);
    }
    private static void FixAntiForgeryTokenMvc1ToMvc2(
        Controller controller, RequestContext requestContext)
    {
        // stuff ....
    }
}

и в ваших «обычных» контроллерах просто есть:1006 *

public class NormalController : BaseController
{
    // all the previous stuff
}

попробуй ...

...