首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >AntiForgeryToken在登录后无效

AntiForgeryToken在登录后无效
EN

Stack Overflow用户
提问于 2012-02-01 13:44:46
回答 2查看 4.5K关注 0票数 13

我有一个表单,用户可以在不登录的情况下发布。然而,如果他的电子邮件被识别,一个密码是必需的。密码表单通过Ajax进行验证,如果成功,则提交主表单。这两种表单都需要有效的AntiForgeryToken。

问题是,密码检查作为一个双产品也签署用户(一个要求从客户端)。这将使令牌无效,并且无法发送主窗体。

我已经尝试以编程的方式生成一个新的令牌,但是我无法让它工作。

对如何解决这个问题有什么想法吗?

终解

我发现问题在输入反射时很有帮助。但是,这也是为什么在正常情况下,您要避免侵入内部类型的主要原因,就是在不同版本之间的程序集之间频繁地处理类型。就像贝蒂建议的那样,用ILSpy来找东西。

这是最后的代码。

代码语言:javascript
复制
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

代码语言:javascript
复制
  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 }));
        }
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2012-02-04 02:53:21

当前用户存储在表单数据中的防伪令牌中,并在回发时与当前用户进行比较。

您应该能够在回发时提取表单令牌,就像Phil在这个职位中那样。

然后使用AntiForgeryDataSerializer类反序列化令牌,更新当前用户,再次序列化它,并在检查之前将其放到表单中。或者完全使用您自己的属性替换验证方法。

或者,您可以尝试使用密码ajax请求发送更新后的令牌,而不是在主窗体回发时更新它,然后更新表单。无论哪种方式,基本方法都是相同的,反序列化、更新用户、序列化、替换令牌。

代码语言:javascript
复制
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是内部类,因此您必须使用一些基本反射来调用它们的方法。

票数 4
EN

Stack Overflow用户

发布于 2013-01-09 21:48:57

AntiForgeryTokenSerializer构造函数更改的最新最终答案:

代码语言:javascript
复制
    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;
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9096769

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档