Asp.net-Mvc
AntiForgeryToken 登錄後無效
我有一個表格,使用者無需登錄即可發布。但是,如果他的電子郵件被辨識,則需要密碼。密碼表單通過 Ajax 驗證,如果成功,則送出主表單。兩種形式都需要有效的 AntiForgeryToken。
問題是,作為副產品的密碼檢查也會讓使用者登錄(來自客戶端的要求)。這會使令牌無效,並且無法發送主表單。
我已經嘗試以程式方式生成一個新令牌,但我無法讓它工作。
關於如何解決這個問題的任何想法?
最終解決方案
我發現這個問題有助於輸入反思。然而,這也是為什麼在正常情況下你會避免破解內部類型的主要原因,是這些類型在版本之間的程序集之間進行了很多處理。正如 Betty 建議的那樣,使用 ILSpy 查找內容。
這是最終程式碼。
if (signIn) FormsAuth.SignIn(user.Email, false); var mvcAssembly = typeof(AntiForgery).Assembly; var afdType = mvcAssembly.GetType("System.Web.Helpers.AntiForgeryData"); string fieldName = Convert.ToString(afdType.InvokeMember( "GetAntiForgeryTokenName", BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, null, null, new object[] { null })); var serializerType = mvcAssembly.GetType("System.Web.Helpers.AntiForgeryDataSerializer"); var serializerCtor = serializerType.GetConstructor(new Type[0]); object serializer = serializerCtor.Invoke(new object[0]); string text = HttpContext.Request.Form[fieldName]; object antiForgeryData = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { text }); afdType.GetProperty("Username").SetValue(antiForgeryData, signIn ? user.Email : string.Empty, null); string newToken = Convert.ToString(serializerType.InvokeMember( "Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { antiForgeryData })); return Content(JsonConvert.SerializeObject(new { success = true, newAntiForgeryToken = newToken }), Constant.JsonContentType);升級網頁 2.0
var mvcAssembly = typeof(AntiForgery).Assembly; var afdType = mvcAssembly.GetType("System.Web.Helpers.AntiXsrf.AntiForgeryToken"); //string fieldName = Convert.ToString(afdType.InvokeMember( // "GetAntiForgeryTokenName", // BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, // null, // null, // new object[] { null })); string fieldName = "__RequestVerificationToken"; var serializerType = mvcAssembly.GetType("System.Web.Helpers.AntiXsrf.AntiForgeryTokenSerializer"); var serializerCtor = serializerType.GetConstructor(new Type[0]); object serializer = serializerCtor.Invoke(new object[0]); string text = HttpContext.Request.Form[fieldName]; string newToken = String.Empty; if (!String.IsNullOrEmpty(text)) { object antiForgeryToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { text }); afdType.GetProperty("Username").SetValue(antiForgeryToken, signIn ? user.Email : string.Empty, null); newToken = Convert.ToString(serializerType.InvokeMember( "Serialize", BindingFlags.InvokeMethod, null, serializer, new[] { antiForgeryToken })); }
目前使用者儲存在表單數據中的防偽令牌中,並在回發時與目前使用者進行比較。
您應該能夠以 Phil Haack 在這篇文章中所做的相同方式在回發時提取表單令牌。
然後使用 AntiForgeryDataSerializer 類對令牌進行反序列化,更新目前使用者,再次對其進行序列化,並將其放回表單中,然後再進行檢查。或者完全使用您自己的屬性替換 validate 方法。
或者,您可以嘗試使用密碼 ajax 請求發回更新的令牌並更新表單,而不是在主表單回發上更新它。無論哪種方式,基本方法都是相同的,反序列化、更新使用者、序列化、替換令牌。
string antiForgeryTokenName = AntiForgeryData.GetAntiForgeryTokenName(null); string text = context.Request.Form[antiForgeryTokenName]; AntiForgeryDataSerializer serializer = new AntiForgeryDataSerializer(); AntiForgeryData antiForgeryData = serializer.Deserialize(text); antiForgeryData.Username = AntiForgeryData.GetUsername(context.User); string newToken = serializer.Serialize(antiForgeryData);AntiForgeryDataSerializer 和 AntiForgeryData 是內部類,因此您必須使用一些基本反射來呼叫它們的方法。