【问题标题】:Patching Asp.net Mvc2 AntiForgeryToken exception修补 Asp.net Mvc2 AntiForgeryToken 异常
【发布时间】:2010-09-28 23:53:02
【问题描述】:

我的问题的一些背景:

Mvc2 中似乎有一个关于ValidateAntiForgeryTokenAttribute 的更改/错误。

从 Mvc1 升级到 Mvc2 时,具有活动会话的用户在使用 ValidateAntiForgeryTokenAttribute 请求页面时会收到以下错误:

无法将“System.Web.UI.Triplet”类型的对象转换为“System.Object[]”类型。

该问题已记录在 here

升级到 Mvc2 后,我们预计我们将受到此问题的严重影响。我编写了一个从 cmets 中的代码派生的修复程序(为后代记录如下)。目前,通过创建 ControllerAsyncController 的子类来调用此代码,并覆盖 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);
                }
            }
        }
    }
}

这样做的连锁反应是我必须更改我的所有控制器类以从我的新的、更正的控制器子类派生。对于打算在大约一个月内弃用的代码来说,这似乎很麻烦。

所以,关于我的问题,我想知道是否有一种侵入性较小的方法来修补现有类,从而不必更改该类的下游用户,也许使用反射?

【问题讨论】:

  • 升级前可以断开大家的连接吗?
  • 如果可能,我们不希望这样做。
  • 我知道这对你的探索没有帮助。我们很幸运能够在大约 3 个月前进行类似升级之前通知所有用户清除他们的缓存/cookie。我绕着圈子试图找到一个可行的解决方案来解决潜在的问题。最后(这是一个只有 50 个用户的业务线应用程序),我们只是通过电子邮件向他们发送了有关如何清除“碎片”的说明。当然,如果您的网站是公共网站,那么上述可能是唯一的行动方案。我会密切关注这一点,作为我感兴趣的一些即将到来的工作的一个地方修复。
  • 另外,您可以使用基本控制器并让所有其他控制器继承自该控制器,从而只需对其进行一次编码,然后在迁移完成后将其从单个位置移除(比如说 4 个月的时间 - 或其他什么)。这将是我的第一个攻击角度(使用类似于您的 OP 的代码)
  • @jim:我认为没有必要清除缓存和 cookie。防伪令牌只是页面中的隐藏输入。当我们升级时,我们几乎没有任何问题;大多数遇到错误的人只是重新加载了页面,然后就可以正常提交了。

标签: asp.net-mvc asp.net-mvc-2 reflection patch antiforgerytoken


【解决方案1】:

花费者,

与其对每个控制器进行编码,不如使用基本控制器并按照以下方式继承:

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 ....
    }
}

在您的“普通”控制器中,只需:

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

试一试……

【讨论】:

  • 这就是我目前的做法。它仍然需要更改所有控制器以从新基础派生。
  • 好的 - 在这种情况下,对基本控制器的单一更改不会渗透到从它继承的所有内容吗?当然,我假设您“总是”有一个基本控制器,因此我的建议是随意的。否则,我想陪审团还没有出来:(
  • 当然......这正是计划,因此这些事情都得到了很好的控制。我真的很想知道是否有一种不那么侵入性的修补坏代码的方法。在有人说不同之前,我很高兴我采取了最好的方法。
  • spender,恕我直言,我认为您采用了最广为人知的方法,因此对于毕竟是暂时的情况,这是最务实的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-01-26
  • 1970-01-01
  • 1970-01-01
  • 2016-02-12
  • 1970-01-01
  • 2018-06-11
  • 2013-01-03
相关资源
最近更新 更多