Asp.net mvc 从Web表单使用MVC HtmlHelper
我正在向混合WebForms/MVC站点添加一些UI功能。在本例中,我将向WebForms页面添加一些AJAX UI特性(通过jQuery),数据来自MVC JsonResult。一切正常,但有一个例外: 我想实现AntiForgeryToken的XSRF保护。我在纯MVC应用程序中结合使用了ValidateAntiForgeryToken属性,但想知道如何在WebForms中实现Html.AntiForgeryToken()方法 我在正确地“模拟”ViewContext/RequestContext时遇到一些问题。我应该如何在WebForms页面中使用HtmlHelpers 编辑:Asp.net mvc 从Web表单使用MVC HtmlHelper,asp.net-mvc,webforms,html-helper,Asp.net Mvc,Webforms,Html Helper,我正在向混合WebForms/MVC站点添加一些UI功能。在本例中,我将向WebForms页面添加一些AJAX UI特性(通过jQuery),数据来自MVC JsonResult。一切正常,但有一个例外: 我想实现AntiForgeryToken的XSRF保护。我在纯MVC应用程序中结合使用了ValidateAntiForgeryToken属性,但想知道如何在WebForms中实现Html.AntiForgeryToken()方法 我在正确地“模拟”ViewContext/RequestCont
我希望从我的WebForms页面检索AntiForgeryToken,而不是从MVC JsonResult中检索。您可以在控制器中创建一个新的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);
默认情况下,ASP.NET WebForms已经包含验证事件和viewstate的措施。在链接的帖子里谈了一点。讨论了XSRF缓解策略,关键方法在MVC源代码中:
GetAntiForgeryTokenAndSetCookie
这将创建名为AntiForgeryData
的内部密封类的实例
实例被序列化为cookie“\uuuu RequestVerificationToken”+应用程序路径的基本64编码版本
AntiForgeryData
的同一实例被序列化为隐藏输入
通过RNGCryptoServiceProvider.GetBytes()
所有这些都可能在WebForms页面中被欺骗,唯一混乱的是隐藏的密封类的序列化。不幸的是,关键方法(GetAntiForgeryTokenAndSetCookie
)依赖于ViewContext.HttpContext.Request
获取Cookie,而Web表单需要使用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方法相同的cookie和HTML
我没有为salt和domain方法烦恼,但它们很容易添加。我知道这是一个老问题,但今天我遇到了这个问题,我想与大家分享一下。我在MVC4中工作,有一个webform控件(.ascx),它在MVC(通过RenderPartial)和WebForms之间共享。在那个对照组中,我需要一个防伪令牌。幸运的是,现在您可以在webforms中使用一个助手,它非常简单:
<%= AntiForgery.GetHtml() %>
这将使您的防伪令牌像在MVC中一样
.据我所知,AntiForgeryToken设置了一个cookie,并注入了一个隐藏的表单字段,因此可以对两者进行比较。这是如何实现的?非常好的链接,谢谢。我希望找到一种专门使用AntiForgeryToken的方法,因为MVC web服务的“消费者”位于WebForms页面上(我不会在MVC中重写)。我也有同样的问题-一个遗留WebForms页面需要使用
AntiForgeryToken
发布到MVC操作。我想将Html.AntiForgeryToken()
添加到WebForms页面,而不在MVC中重写它。您好,我刚刚尝试在WebForms应用程序(.NET 4.0,MVC 3.0)中实现这一点,并从这一行中得到一个“对象引用未设置为对象实例”错误:var serializerCtor=serializerType.GetConstructor(新类型[0]);有人能帮忙吗?我在这里有点不知所措。@BFOT这是在ASP.NET2、MVC1上写的,完全是一种黑客行为——我在思考他们的防伪令牌内容,但这都是私有方法。很可能这需要对ASP和MVC的每个新版本进行更新,下载MVC 3源代码,看看这些方法是如何改变的-如果我们很幸运的话,他们甚至可能已经公开了它们,以便WebForms可以使用它们。感谢您的回复。这个周末我将看一看最新的MVC源代码,看看我是否能解决这个问题。如果有空,请随时发布上述代码的修订版本。;)看我的帖子;有一个新的受支持的帮助程序,您可以使用它来获取webforms页面中的功能。@BFOT@pvanhuten在MVC3中有一个更好的方法,现在内置了一个完全受支持的AntiForgery.GetHtml()
方法。我的解决方案是一个仅适用于MVC1-2的垫片。非常好,这是解决WebForms 2/MVC 3及更高版本中问题的更好方法。
<%= AntiForgery.GetHtml() %>