Why does login redirect fail in MVC when using a F

2019-09-08 08:14发布

Using forms authentication, I am filling the UserData field with a serialized CustomIdentitySerializer object.

The user logs in, and I have verified that Membership.ValidateUser() works just fine.

I then begin populating the CustomIdentitySerializer object and send it off to a static UpdateAuthenticationTicket method in a static UserContext class to test data retention - After Login() / 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");

Helper method:

/// <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 can change through the user's time on the site, so we will reuse this method whenever that data needs to be changed.

In Global.asax.cs I have:

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;
        }
    }
}

I think this may have to do with the Principal provider not being set properly or rewritten.

After the cookie value is set, Application_AuthenticateRequest get's hit, followed by Application_PostAuthenticateRequest. This process occurs twice, then back to the Login page.

It seems that the code in Application_AuthenticateRequest is not useful, as I'm not setting any properties there anyway.

The problem is that after the user is actually logged in, the RedirectToAction goes back to http://localhost:1982/Account/Login?ReturnUrl=%2fDashboard rather than appropriate page.

Are there any foreseeable issues in having updating the cookie from the static UserContext class?

Some assistance on this please on how to clean this up and getting working?

Thanks.

-- UPDATE --

In looking at the authCookie object in Application_PostAuthenticateRequest, Expires is set to {1/1/0001 12:00:00 AM}. Regardless, the authTicket cookie expiration is correct - 30 minutes from time of creation. So that cookie is there.

What else?

-- UPDATE --

In looking at the cookie version, I notice a difference. As soon as I set the cookie in UpdateAuthenticationTicket, I check:

authTicket.Version = 

and

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

Not sure why there are two versions, if someone can please explain that as well? I tried setting the cookie with version=2 - same issue.

1条回答
唯我独甜
2楼-- · 2019-09-08 08:23

In further messing around with this, I moved the code over from Application_PostAuthenticateRequest to Application_AuthenticateRequest and everything seems to work fine now:

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;
        }
    }
}

Can someone please explain why this is, as so many of the references I have found for this indicate to put this code in Application_PostAuthenticateRequest???

查看更多
登录 后发表回答