为什么在使用 FormsAuthentication CustomIdentity 和更新 AuthTicket UserData 时登录重定向在 MVC 中失败?

Why does login redirect fail in MVC when using a FormsAuthentication CustomIdentity and updating AuthTicket UserData?

使用表单身份验证,我用序列化的 CustomIdentitySerializer 对象填充 UserData 字段。

用户登录,我已经验证 Membership.ValidateUser() 工作正常。

然后我开始填充 CustomIdentitySerializer 对象并将其发送到静态 UserContext class 中的静态 UpdateAuthenticationTicket 方法以测试数据保留 - 登录后( ) / User.Identity.IsAuthenticated:

// set auth ticket
UserContext.UpdateAuthenticationTicket(user.Username, serializeModel);

// get custom identity - user properties
string userName = UserContext.Identity.UserName;

// reset login attempts
Session["_LoginAttempts"] = 0;

return RedirectToAction("Index", "Dashboard");

辅助方法:

/// <summary>
/// As we will want to update the UserData portion of the cookie while the 
/// user is logged, this will be reused
/// 
/// Auth Ticket/Cookie's UserData property is the CustomIdentitySerializer object
/// </summary>
/// <param name="userName"></param>
/// <param name="userData"></param>
public static void UpdateAuthenticationTicket(string userName, CustomIdentitySerializer userData)
{
    //var authUser = GetUser(userName);
    JavaScriptSerializer serializer = new JavaScriptSerializer();
    string userDataSerialized = serializer.Serialize(userData);

    FormsAuthenticationTicket authTicket = new FormsAuthenticationTicket(1,
        userName,
        DateTime.Now,
        DateTime.Now.AddMinutes(30),
        false,
        userDataSerialized,
        FormsAuthentication.FormsCookiePath);

        // encrypt the ticket
        string encTicket = FormsAuthentication.Encrypt(authTicket);

        // create/set the cookie
        HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
        HttpContext.Current.Response.Cookies.Add(faCookie);

    }

userData 可以通过用户在网站上的时间进行更改,因此我们将在需要更改数据时重复使用此方法。

Global.asax.cs 我有:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null)
    {
        FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);

        var fromsIdentity = new FormsIdentity(authTicket);

        // Get the GenericPrincipal identity  
        IIdentity ui = HttpContext.Current.User.Identity;  

        CustomIdentity customIdentity = new CustomIdentity(ui.Name);
        CustomPrincipal customPrincipal = new CustomPrincipal(ui.Name);

        string userData = ((FormsIdentity)(Context.User.Identity)).Ticket.UserData;

        // Set custom principal 
        HttpContext.Current.User = customPrincipal;
    }
}

/// <summary>
/// Since we set current project and other custom user fields  through the user experience,
/// these are saved in the authticket/cookie's UserData field as a CustomIdentitySerializer object type
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
protected void Application_PostAuthenticateRequest(Object sender, EventArgs e)
{
    if (HttpContext.Current.User.Identity.IsAuthenticated)
    {
        HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

        if (authCookie != null)
        {
            // get the current cookie
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            var fromsIdentity = new FormsIdentity(authTicket);
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            CustomIdentitySerializer userData = serializer.Deserialize<CustomIdentitySerializer>(authTicket.UserData);

            CustomPrincipal customPrincipal = new CustomPrincipal(HttpContext.Current.User.Identity.Name);
            customPrincipal.CustomIdentity.FirstName = userData.FirstName;
            customPrincipal.CustomIdentity.LastName = userData.LastName;
            customPrincipal.CustomIdentity.CurrentProject = userData.CurrentProject;

            HttpContext.Current.User = customPrincipal;
        }
    }
}

我认为这可能与未正确设置或重写主要提供程序有关。

设置 cookie 值后,Application_AuthenticateRequest 获得命中,然后是 Application_PostAuthenticateRequest。此过程发生两次,然后返回登录页面。

似乎 Application_AuthenticateRequest 中的代码没有用,因为我没有在那里设置任何属性。

问题是在用户实际登录后,RedirectToAction 返回到 http://localhost:1982/Account/Login?ReturnUrl=%2fDashboard 而不是适当的页面。

从静态 UserContext class 更新 cookie 是否存在任何可预见的问题?

关于如何清理和开始工作请提供一些帮助?

谢谢。

--更新--

在查看 Application_PostAuthenticateRequest 中的 authCookie 对象时,Expires 被设置为 {1/1/0001 12:00:00 AM}。无论如何,authTicket cookie 过期时间是正确的 - 从创建时间算起 30 分钟。所以那个 cookie 就在那里。

还有什么?

--更新--

在查看 cookie 版本时,我注意到了一个不同之处。一旦我在 UpdateAuthenticationTicket 中设置了 cookie,我就会检查:

authTicket.Version = 

FormsAuthentication.Decrypt(HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName].Value).Version = 2

不知道为什么有两个版本,如果有人能解释一下?我尝试使用 version=2 设置 cookie - 同样的问题。

为了进一步解决这个问题,我将代码从 Application_PostAuthenticateRequest 移到了 Application_AuthenticateRequest,现在一切似乎都运行良好:

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{

    HttpCookie authCookie = HttpContext.Current.Request.Cookies[FormsAuthentication.FormsCookieName];

    if (authCookie != null && HttpContext.Current.User.Identity.IsAuthenticated)
    {

        if (authCookie != null)
        {
            // get the current cookie
            FormsAuthenticationTicket authTicket = FormsAuthentication.Decrypt(authCookie.Value);
            var fromsIdentity = new FormsIdentity(authTicket);
            JavaScriptSerializer serializer = new JavaScriptSerializer();
            CustomPrincipal customPrincipal = new CustomPrincipal(HttpContext.Current.User.Identity.Name);
            CustomIdentitySerializer userData = serializer.Deserialize<CustomIdentitySerializer>(authTicket.UserData);
            if (userData != null)
            {
                customPrincipal.CustomIdentity.FirstName = userData.FirstName;
                customPrincipal.CustomIdentity.LastName = userData.LastName;
                customPrincipal.CustomIdentity.CurrentProject = userData.CurrentProject;
            }

            HttpContext.Current.User = customPrincipal;
        }
    }
}

谁能解释一下这是为什么,因为我找到的很多参考资料都表明要将这段代码放在 Application_PostAuthenticateRequest???