Reputation: 817
I'm attempting to save the FormsAuthenticationTicket to a cookie using the following code (in AccountController.cs):
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
(1, user.UserEmail, DateTime.Now,
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
false, null);
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie faCookie = new HttpCookie(FormsAuthentication.FormsCookieName,
ticket.ToString());
HttpContext.Response.Cookies.Add(faCookie);
if (Url.IsLocalUrl(returnUrl) && returnUrl.Length > 1 && returnUrl.StartsWith("/")
&& !returnUrl.StartsWith("//") && !returnUrl.StartsWith("/\\"))
{
return Redirect(returnUrl);
}
else
{
return RedirectToAction("Index", "Home");
}
As I step through the debugger, everything seems just fine. Until I get to Application_AuthenticateRequest
, where I try to retrieve the cookie:
HttpCookie authCookie = Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie != null)
{
//do stuff here
}
When I look in the Cookies collection, there's just nothing there. I can add another normal cookie in the AccountController code and it shows up just fine. The problem persists whether or not I include UserData, so I don't think it's a size issue.
Thanks for any insight you can provide.
Upvotes: 2
Views: 3040
Reputation: 11
In your code to write the cookie, you cannot pass a null to the userData parameter with an encrypted cookie. The IsPersistent as false is fine.
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket
(1, user.UserEmail, DateTime.Now,
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes),
false, null);
Do something like this below: In my example, you can replace userData.ToString() with an empty string. Just don't pass it a null! That should fix your problem.
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // version
userId.UserEmail, // a unique value that identifies the user
DateTime.Now, // created
DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes), // expires
false, // persistent?
userData.ToString(), // user specific data (optional) //NOTE: DO NOT pass NULL as encrypted string value will become NULL (argh)
FormsAuthentication.FormsCookiePath // the path for the cookie
);
Then in your global.asax.cs You will be checking that cookie in the FormsAuthentication_OnAuthenticate event Your code will vary here as I have written a custom forms authentication and am using a userId rather than email as in your case.
Take note to the following logic that fails if you pass null for your UserData parameter when writing the auth cookie.
if (authCookie == null || authCookie.Value == "")
{
return;
}
Here is the full event in the globalasax.cs file:
protected void FormsAuthentication_OnAuthenticate(Object sender, FormsAuthenticationEventArgs e)
{
//STEP #1 of Authentication/Authorization flow
//Reference: http://msdn.microsoft.com/en-us/library/ff649337.aspx
//==================================================================
if (FormsAuthentication.CookiesSupported == true)
{
//Look for an existing authorization cookie when challenged via [Authorize]
HttpCookie authCookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName];
if (authCookie == null || authCookie.Value == "")
{
return;
}
FormsAuthenticationTicket authTicket = null;
try
{
//Reading from the ticket
authTicket = FormsAuthentication.Decrypt(authCookie.Value);
//Check the Cookiename (which in this case is UserId). If it is null, then we have an issue
if (authTicket.Name == null)
{
FormsAuthentication.SignOut();
authCookie.Value = null;
}
}
catch (Exception ex)
{
//Unable to decrypt the auth ticket
return;
}
//get userId from ticket
string userId = authTicket.Name;
Context.User = new GenericPrincipal(
new System.Security.Principal.GenericIdentity(userId, "MyCustomAuthTypeName"), authTicket.UserData.Split(','));
//We are officially 'authenticated' at this point but not neccessarily 'authorized'
}
else
{
throw new HttpException("Cookieless Forms Authentication is not supported for this application.");
}
}
Upvotes: 1
Reputation: 7391
Although your authentication ticket is set to be persistent and has an expires date, the actual cookie doesn't.
Add something like this when creating your cookie:
var faCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket)
{
Expires = ticket.Expiration
};
Upvotes: 1
Reputation: 1796
You are setting the isPersistent parameter to false when you are creating your FormsAuthenticationTicket. This parameter should be set to true.
Upvotes: 0
Reputation: 2932
The max size of a cookie is 4096 bytes. If it's above this the cookie wont be saved.
Check the Cookie size using the following:
int cookieSize = System.Text.UTF8Encoding.UTF8.GetByteCount(faCookie.Values.ToString());
Upvotes: 3
Reputation: 1038710
You are adding the cookie to the response. Once you have done that make sure you have redirected after immediately. It is only on the subsequent request that you can hope to read it from the Request.Cookies
collection.
Upvotes: 1