Asp.net-Mvc

AntiForgeryToken 登錄後無效

  • February 20, 2013

我有一個表格,使用者無需登錄即可發布。但是,如果他的電子郵件被辨識,則需要密碼。密碼表單通過 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 是內部類,因此您必須使用一些基本反射來呼叫它們的方法。

引用自:https://stackoverflow.com/questions/9096769