2

I am using forms authentication for an MVC website and I am having a problem adding Cookies, I am using an Encrypted Forms Authentication Ticket and adding it to the Cookies but when inspecting my cookies it is there (by name "AuthCookie") but the value is always null and the Expires date is always set to "01/01/0001 00:00"... here is my Login controller code:

[HttpPost]
public ActionResult Index(Login login, string returnUrl)
{
    if (ModelState.IsValid)
        try
        {
            User user = UserManager.Login(login.Username, login.Password);
            string serialUser = Serialize.SerializeToString(user);
            string ticket = FormsAuthentication.Encrypt(
                new FormsAuthenticationTicket(1, login.Username, DateTime.Now, DateTime.Now.AddMinutes(20.0), login.RemeberMe, serialUser));

            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, ticket) { Expires = DateTime.Now.AddMinutes(20) };
            Response.Cookies.Add(cookie);


            if (String.IsNullOrEmpty(returnUrl))
                return RedirectToAction("Index", "Home");
            else
                return Redirect(returnUrl);
        }
        catch (LoginFailedException)
        {
            ModelState.AddModelError("", "Login failed: Invalid Username or Password.");
            return View(login);
        }
    else
        return View(login);

}

At first I assumed the encrypted string was not working due to the length but I have tested this by creating a simple test cooke and I am getting the same result.

Can anyone help

Andy Clark
  • 3,363
  • 7
  • 27
  • 42
  • 1
    Is there a reason why you aren't using FormsAuthentication.SetAuthCookie()? – rfmodulator Jan 02 '12 at 00:13
  • using SetAuthCookie() you dont get access to the userData... which I will be using to store the UserRole and other optional data for IPrincipal and IIdentity – Andy Clark Jan 02 '12 at 00:15
  • 1
    I see. I'm not sure if it's a good idea to store role data on the client. :) Encrypted or otherwise. – rfmodulator Jan 02 '12 at 00:17
  • Any suggestion where to store data without going to the database with every page request? I have been googling for days on forms authentication with using the built in membership and everything is a bit scetchy – Andy Clark Jan 02 '12 at 00:19
  • If you want some degree of security, you're going to the data store every time, like it or not... – rfmodulator Jan 02 '12 at 00:20
  • still doesnt solve my cookies problem – Andy Clark Jan 02 '12 at 00:23
  • That's why it's not an answer. :) – rfmodulator Jan 02 '12 at 00:25
  • 1
    Regarding roles, you could implement a custom role provider that caches the role information. That's a lot cleaner, and more secure than adding it to the cookie. – Erik Funkenbusch Jan 02 '12 at 00:32
  • Another option, write a wrapper around Session that looks for the role in session, and if it's not there gets it from Roles. That way it only retrieves role information the first time, or when the session expires (but authentication is still valid) – Erik Funkenbusch Jan 02 '12 at 00:39
  • If you are using Session that it will save your database trip as well as you don't have to store roles in cookie. – dotnetstep Jan 02 '12 at 02:24

1 Answers1

3

When you call Redirect() or RedirectToAction(), you're terminating the response so the cookies aren't sent to the client. Some solutions:

  1. Use TempData to persist the information across the direct, writing the Cookie in the action you redirect to.
  2. Take a look at the way Forms Authentication cookie information is written in the NerdDinner code on CodePlex.
  3. As mentioned in the comments, you can persist role information in Session. The recommendation to store the role information in Session and retrieve from Roles if not found would work, but I'd start by using the membership system as-is and performance tuning later if you see that it's a problem, rather than assuming it will be.
Jon Galloway
  • 52,327
  • 25
  • 125
  • 193
  • I am now using a Custom Role Provider as mentioned above and this has solved my roles problem really well. As regrads to setting my Authentication ticket I looked at nerd dinner example (thanks for that) and it looks like this is simply setting the Auth cookie in the same way which is: Validate the User... Set the Auth Cookie... Redirect to the original Page requested... – Andy Clark Jan 10 '12 at 11:21
  • @JonGalloway. The issue with solution number 3 is that you can't get to the session on the "AuthenticateRequest_handler", which is typically used to set the Thread.CurrentPrincipal (for which you need roles). – tggm Jul 24 '12 at 10:48