我正在为混合WebForms / MVC网站添加一些UI功能。在这种情况下,我将一些AJAX UI功能添加到WebForms页面(通过jQuery),数据来自MVC JsonResult。一切都在100%工作,有一个例外:
我想实施XSRF保护AntiForgeryToken。我已经将它与我的纯MVC应用程序中的ValidateAntiForgeryToken属性结合使用,但想知道如何在WebForms中实现Html.AntiForgeryToken()方法。 Here’s an example using a UrlHelper。
我正在让ViewContext / RequestContext“嘲笑”正确的一些麻烦。如何在WebForms页面中使用HtmlHelpers?
编辑:
我正在从我的WebForms页面检索AntiForgeryToken,而不是从MVC JsonResult中检索。
解决方法
关键的方法是在MVC源代码中:GetAntiForgeryTokenAndSetCookie
这将创建一个称为AntiForgeryData的内部密封类的实例。
该实例被序列化为一个基于应用程序路径的64位编码版本的cookie“__RequestVerificationToken_”。
相同的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,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",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,serializer,new object[] { cookie.Value }); } else { // cookieToken = AntiForgeryData.NewToken(); cookieToken = afdType.InvokeMember( "NewToken",BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod,new object[0]); // string cookieValue = Serializer.Serialize(cookieToken); string cookieValue = Convert.ToString(serializerType.InvokeMember("Serialize",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,formToken,new object[] { DateTime.Now }); afdType.InvokeMember("Salt",new object[] { null }); // string formValue = Serializer.Serialize(formToken); string formValue = Convert.ToString(serializerType.InvokeMember("Serialize",new object[] { formToken })); return formValue; } }
用法类似于MVC:
WebFormAntiForgery.AntiForgeryToken()
它创建与MVC方法相同的cookie和相同的HTML。