Pergunta

So, what I am trying to accomplish is a basic "remember me" style action for users of my application.

I have completed writing everything so far, and it is working as expected most of the time. Occasionally though, the method to check for the persistent Forms Authentication ticket doesn't auto login, and I can't figure out why it is only happening occasionally.

To test my code, what I have done is start the debugger, manually kill my session cookie in chrome's dev tools, then reload the page. Stepping through the code, it enters into the auto login method as expected and proceeds to reset my session data. However, if I wait an inordinate amount of time, like 4 hours perhaps, and try the same thing it does not auto reset my session. (Assuming that i've left the debugger running for that amount of time).

EDIT: For clarity's sake, when this error is happening, I can open the dev tools and see that the authentication ticket is still available. It's just the code to reset my session is either not running, for erroring out somewhere. Due to the infrequency in which this is happening, it's hard to track down.

So, onto the code.

I'm calling the static void auto login method in the controller's constructor, and passing the httpcontext into the auto login method.

Controller

public class SiteController : Controller
{
    public SiteController()
    {
       this.UserAutoLogin(System.Web.HttpContext.Current);
    }

    // GET: /Site/
    public ActionResult Index()
    {
        ViewBag.CatNav = this.RenderNavCategories();
        return View();
    }
}

Auto Login Code

public static void UserAutoLogin(this Controller Controller, System.Web.HttpContext context)
{
    HttpCookie cookie = HttpContext.Current.Request.Cookies.Get(FormsAuthentication.FormsCookieName);

    if (cookie != null)
    {
        FormsAuthenticationTicket ticket = FormsAuthentication.Decrypt(cookie.Value);

        if (ticket != null)
        {
            if (ticket.Name.Length > 0)
            {
                try
                {
                    if (context.Session["UserName"] == null)
                    {
                        //get user from db
                        PersonRepository PersonRepo = new PersonRepository();
                        PersonModel Member = PersonRepo.GetUserUserName(ticket.Name);

                        if (Member.FirstName != null) //if this is null...then the cookie is wrong, so don't do shit
                        {
                            //Set the session parameters
                            context.Session["FirstName"] = Member.FirstName;
                            context.Session["LastName"] = Member.LastName;
                            context.Session["UserId"] = Member.Id;
                            context.Session["UserName"] = Member.Username;
                            context.Session["Email"] = Member.Email;
                            context.Session["IsUser"] = 1;
                            context.Session["Zip"] = Member.Zip;

                            FormsAuthentication.SignOut();
                            FormsAuthentication.SetAuthCookie(Member.Username, true);
                        }
                    }
                }
                catch (Exception ex)
                {
                    // don't do anything for now - do something smart later :)                        
                    Console.WriteLine(ex.ToString());
                }
            }
        }
    }
}
Foi útil?

Solução

Because when IIS is recycling the app, a new machine key is generated. The FormsAuthentication ticket is signed using that key so when the key changes the old ticket isn't recognized. You need to use a fixed machine key.

Edit: Removed link to key generator site (now defunct)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top