我有一个表单,用户可以在不登录的情况下发布。然而,如果他的电子邮件被识别,一个密码是必需的。密码表单通过Ajax进行验证,如果成功,则提交主表单。这两种表单都需要有效的AntiForgeryToken。
问题是,密码检查作为一个双产品也签署用户(一个要求从客户端)。这将使令牌无效,并且无法发送主窗体。
我已经尝试以编程的方式生成一个新的令牌,但是我无法让它工作。
对如何解决这个问题有什么想法吗?
终解
我发现这问题在输入反射时很有帮助。但是,这也是为什么在正常情况下,您要避免侵入内部类型的主要原因,就是在不同版本之间的程序集之间频繁地处理类型。就像贝蒂建议的那样,用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);升级为WebPages 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 }));
}发布于 2012-02-04 02:53:21
当前用户存储在表单数据中的防伪令牌中,并在回发时与当前用户进行比较。
您应该能够在回发时提取表单令牌,就像Phil在这个职位中那样。
然后使用AntiForgeryDataSerializer类反序列化令牌,更新当前用户,再次序列化它,并在检查之前将其放到表单中。或者完全使用您自己的属性替换验证方法。
或者,您可以尝试使用密码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是内部类,因此您必须使用一些基本反射来调用它们的方法。
发布于 2013-01-09 21:48:57
AntiForgeryTokenSerializer构造函数更改的最新最终答案:
const string serializerAssembly = "System.Web.Helpers.AntiXsrf.AntiForgeryTokenSerializer";
const string cryptoAssembly = "System.Web.Helpers.AntiXsrf.MachineKey40CryptoSystem";
const string token = "System.Web.Helpers.AntiXsrf.AntiForgeryToken";
const string fieldName = "__RequestVerificationToken";
Assembly mvcAssembly = typeof (AntiForgery).Assembly;
Type afdType = mvcAssembly.GetType(token);
Type serializerType = mvcAssembly.GetType(serializerAssembly);
Type cryptoType = mvcAssembly.GetType(cryptoAssembly);
var constructors = serializerType.GetConstructors(BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance);
ConstructorInfo cryptoConstructor = cryptoType.GetConstructor(new Type[0]);
var crypto = cryptoConstructor.Invoke(new object[0]);
object serializer = constructors[0].Invoke(new object[] { crypto });
string text = currentContext.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}));
}
return newToken;https://stackoverflow.com/questions/9096769
复制相似问题