【发布时间】:2010-09-28 23:53:02
【问题描述】:
我的问题的一些背景:
Mvc2 中似乎有一个关于ValidateAntiForgeryTokenAttribute 的更改/错误。
从 Mvc1 升级到 Mvc2 时,具有活动会话的用户在使用 ValidateAntiForgeryTokenAttribute 请求页面时会收到以下错误:
无法将“System.Web.UI.Triplet”类型的对象转换为“System.Object[]”类型。
该问题已记录在 here。
升级到 Mvc2 后,我们预计我们将受到此问题的严重影响。我编写了一个从 cmets 中的代码派生的修复程序(为后代记录如下)。目前,通过创建 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);
}
}
}
}
}
这样做的连锁反应是我必须更改我的所有控制器类以从我的新的、更正的控制器子类派生。对于打算在大约一个月内弃用的代码来说,这似乎很麻烦。
所以,关于我的问题,我想知道是否有一种侵入性较小的方法来修补现有类,从而不必更改该类的下游用户,也许使用反射?
【问题讨论】:
-
升级前可以断开大家的连接吗?
-
如果可能,我们不希望这样做。
-
我知道这对你的探索没有帮助。我们很幸运能够在大约 3 个月前进行类似升级之前通知所有用户清除他们的缓存/cookie。我绕着圈子试图找到一个可行的解决方案来解决潜在的问题。最后(这是一个只有 50 个用户的业务线应用程序),我们只是通过电子邮件向他们发送了有关如何清除“碎片”的说明。当然,如果您的网站是公共网站,那么上述可能是唯一的行动方案。我会密切关注这一点,作为我感兴趣的一些即将到来的工作的一个地方修复。
-
另外,您可以使用基本控制器并让所有其他控制器继承自该控制器,从而只需对其进行一次编码,然后在迁移完成后将其从单个位置移除(比如说 4 个月的时间 - 或其他什么)。这将是我的第一个攻击角度(使用类似于您的 OP 的代码)
-
@jim:我认为没有必要清除缓存和 cookie。防伪令牌只是页面中的隐藏输入。当我们升级时,我们几乎没有任何问题;大多数遇到错误的人只是重新加载了页面,然后就可以正常提交了。
标签: asp.net-mvc asp.net-mvc-2 reflection patch antiforgerytoken