【问题标题】:MVC4 - Setting custom user data in forms authentication ticket causes the forms authentication cookie to not get set?MVC4 - 在表单身份验证票证中设置自定义用户数据会导致表单身份验证 cookie 未设置?
【发布时间】:2017-11-20 10:45:58
【问题描述】:

我的旧版 MVC4 应用程序使用表单身份验证。当我尝试创建以下自定义 FormsAuthenticationTicket 时,cookie 会在响应中返回,但从未由浏览器设置。请注意,我正在尝试将 OpenID Connect id_token 存储在 cookie 中,这依赖于 FormsAuthenticationTicket 类提供的加密。

//Yes you can decode it - it's just test data
string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA1M2JjYTgzNzZmZjhlNTM5MWVkYzMxYWJkMjU5YzBjIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDc1ODExMjcsImV4cCI6MTUwNzU4MTQyNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaW1wbGljaXQiLCJub25jZSI6IjE1MDc1ODExMjA5MDMwMDQ0MDUzNDkzNjk3ODUzMTYiLCJpYXQiOjE1MDc1ODExMjcsImF0X2hhc2giOiJVWm5SeU1pXzVyUEN6NWduYmt5c09BIiwic2lkIjoiOTExYjI1OGQ5OGNiYzRlYzVkYTFiNmFkYzhiMmRjNTUiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTA3NTgxMTI3LCJpZHAiOiJsb2NhbCIsIm5hbWUiOiJ4Iiwid2Vic2l0ZSI6Imh0dHBzOi8vYWxpY2UuY29tIiwicm9sZSI6ImFkbWluIiwibW9kZWxBY2Nlc3MiOlsiMTIzNCIsIjU2NzgiXSwiY29ubmVjdGlvblN0cmluZyI6InNvbWVNb2RlbENvbm5lY3Rpb25TdHJpbmciLCJhbXIiOlsicHdkIl19.SwTIU1dP1FifCcXVNHkbIGshQiGIjfaa7UAWOrtqKb-FqMMrkvJx_Wa3W19r6NeNwc8mo2go6AFwwu_WM0TF1VJBO1pfmvX35oKgjdTTSqrSmMo5R9_rcywm5YKwVYzmvDqRjPfhZksXkIOuTIk3JOemLrKqw6VIHPyFYV6ZYSK6ZxTpxx50Yz90MmEOBDsTc0GZpQbeZmzyDkBe-iD9uVnlPN2UHz_UuMF__yfmzjGROKLpvem36TKSMa1mEJE7DVxJkexmbxQe3CVwZeIU3iPKloabSReaLCJLqINeI0ikGa4x6PbgfjiP1TPVhIP6i8zUp47lSavGgyy0XVFGtQ";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                            1,
                            model.UserName,
                            DateTime.Now,
                            DateTime.Now.AddDays(30),
                            true,
                            idToken,
                            FormsAuthentication.FormsCookiePath);
                        // Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
this.Response.Cookies.Add(new HttpCookie("TEST", encTicket));

起初我认为这可能是因为长度。但我读到 cookie 的最大长度是 4096 字节。 idToken 只有 983 个字节。

有趣的是,如果我将数据变小(将 idToken 更改为 684 字节),一切都会按预期工作。这是一个工作示例:

//Shortened the idToken (for the sake of the example)
string idToken = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjA1M2JjYTgzNzZmZjhlNTM5MWVkYzMxYWJkMjU5YzBjIiwidHlwIjoiSldUIn0.eyJuYmYiOjE1MDc1ODExMjcsImV4cCI6MTUwNzU4MTQyNywiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1MDAwIiwiYXVkIjoiaW1wbGljaXQiLCJub25jZSI6IjE1MDc1ODExMjA5MDMwMDQ0MDUzNDkzNjk3ODUzMTYiLCJpYXQiOjE1MDc1ODExMjcsImF0X2hhc2giOiJVWm5SeU1pXzVyUEN6NWduYmt5c09BIiwic2lkIjoiOTExYjI1OGQ5OGNiYzRlYzVkYTFiNmFkYzhiMmRjNTUiLCJzdWIiOiIxIiwiYXV0aF90aW1lIjoxNTA3NTgxMTI3LCJpZHAiOiJsb2NhbCIsIm5hbWUiOiJ4Iiwid2Vic2l0ZSI6Imh0dHBzOi8vYWxpY2UuY29tIiwicm9sZSI6ImFkbWluIiwibW9kZWxBY2Nlc3MiOlsiMTIzNCIsIjU2NzgiXSwiY29ubmVjdGlvblN0cmluZyI6InNvbWVNb2RlbENvbm5lY3Rpb25TdHJpbmciLCJhbXIiOlsicHdkIl19.SwTIU1dP1FifCcXVNHkbIGshQiGIjfaa7UAWOrtqKb-";

FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                            1,
                            model.UserName,
                            DateTime.Now,
                            DateTime.Now.AddDays(30),
                            true,
                            idToken,
                            FormsAuthentication.FormsCookiePath);
// Encrypt the ticket.
string encTicket = FormsAuthentication.Encrypt(ticket);
// Create the cookie.
this.Response.Cookies.Add(new HttpCookie("TEST", encTicket));

我解密数据如下:

HttpCookie cookie = HttpContext.Current.Request.Cookies["TEST"];
if (cookie != null)
{
    Debug.WriteLine("Found Cookie Application_PostAuthenticateRequest");

    // Get the forms authentication ticket.
    FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(cookie.Value);
    if (authTicket == null)
    {
          Debug.WriteLine("auth ticket was null");
    }
    else
    {
          Debug.WriteLine("printing auth ticket");
          Debug.WriteLine(authTicket.UserData);
    }
}
else
{
     Debug.WriteLine("No Cookie Application_PostAuthenticateRequest");
}

尽管 cookie 远低于最大限制,为什么第一个示例不起作用?

【问题讨论】:

    标签: c# asp.net-mvc asp.net-mvc-4 forms-authentication


    【解决方案1】:

    我在深入研究 ASP.NET 身份验证 cookie 时遇到了这个问题。根本原因是 ASP.NET 用于将其转换为 cookie 的编码导致您的 983b 数据在最终的在线 cookie 中占用了 3936b。

    原因是双重的。

    1) ASP.NET cookie 将数据字符串作为 UTF-16LE 字符串序列化到 cookie 有效负载中。 see reference source

    这导致您的 983b 被写入为 7 位编码长度 (0x5707),后跟 1966b(983 个 UTF-16LE 字符),在 1968b 编码之前的总大小,存储空间增加 2:1。

    2) 加密后的整个 cookie 被写为十六进制字符串,这意味着这些 1968b 中的每一个都在最终 cookie 中表示为两个字符 0..9A..F(例如:A1B2C3..),导致总3936b 的 cookie 中的大小,存储空间增加 4:1。

    当然,该 cookie 中还有其他内容,例如过期日期、用户名等,这意味着您的 983b 数据很快就会超过 4kb cookie 的限制。

    这似乎可以解释关于 userdata on the docs page 的 dotnet 评论

    您应该限制存储在 UserData 属性中的数据量。您必须确保 UserData 属性的大小不会导致 cookie 无效或 URL 过长。

    因为看起来每 1 个字节的 userdata 会产生 4 个字节的 cookie。

    分享了很久,因为我希望这篇文章在 48 小时前就已经存在了。

    【讨论】:

      【解决方案2】:

      问题是加密之后数据太大了。您必须限制放入FormsAuthenticationTicket 的数据量。如果您在限制范围内,那么一切都会按预期进行。

      【讨论】:

        猜你喜欢
        • 2013-09-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-12
        • 1970-01-01
        • 1970-01-01
        • 2014-12-27
        相关资源
        最近更新 更多