How can I create persistent cookies in ASP.NET? - asp.net

I am creating cookies with following lines:
HttpCookie userid = new HttpCookie("userid", objUser.id.ToString());
userid.Expires.AddYears(1);
Response.Cookies.Add(userid);
Now how can I make it persistent?
If I visit the same page again after closing the browser, I'm unable to get it back.

Here's how you can do that.
Writing the persistent cookie.
//create a cookie
HttpCookie myCookie = new HttpCookie("myCookie");
//Add key-values in the cookie
myCookie.Values.Add("userid", objUser.id.ToString());
//set cookie expiry date-time. Made it to last for next 12 hours.
myCookie.Expires = DateTime.Now.AddHours(12);
//Most important, write the cookie to client.
Response.Cookies.Add(myCookie);
Reading the persistent cookie.
//Assuming user comes back after several hours. several < 12.
//Read the cookie from Request.
HttpCookie myCookie = Request.Cookies["myCookie"];
if (myCookie == null)
{
//No cookie found or cookie expired.
//Handle the situation here, Redirect the user or simply return;
}
//ok - cookie is found.
//Gracefully check if the cookie has the key-value as expected.
if (!string.IsNullOrEmpty(myCookie.Values["userid"]))
{
string userId = myCookie.Values["userid"].ToString();
//Yes userId is found. Mission accomplished.
}

Although the accepted answer is correct, it does not state why the original code failed to work.
Bad code from your question:
HttpCookie userid = new HttpCookie("userid", objUser.id.ToString());
userid.Expires.AddYears(1);
Response.Cookies.Add(userid);
Take a look at the second line. The basis for expiration is on the Expires property which contains the default of 1/1/0001. The above code is evaluating to 1/1/0002. Furthermore the evaluation is not being saved back to the property. Instead the Expires property should be set with the basis on the current date.
Corrected code:
HttpCookie userid = new HttpCookie("userid", objUser.id.ToString());
userid.Expires = DateTime.Now.AddYears(1);
Response.Cookies.Add(userid);

FWIW be very careful with storing something like a userid in a cookie unencrypted. Doing this makes your site very prone to cookie poisoning where users can easily impersonate another user. If you are considering something like this I would highly recommend using the forms authentication cookie directly.
bool persist = true;
var cookie = FormsAuthentication.GetAuthCookie(loginUser.ContactId, persist);
cookie.Expires = DateTime.Now.AddMonths(3);
var ticket = FormsAuthentication.Decrypt(cookie.Value);
var userData = "store any string values you want inside the ticket
extra than user id that will be encrypted"
var newTicket = new FormsAuthenticationTicket(ticket.Version, ticket.Name,
ticket.IssueDate, ticket.Expiration, ticket.IsPersistent, userData);
cookie.Value = FormsAuthentication.Encrypt(newTicket);
Response.Cookies.Add(cookie);
Then you can read this at any time from an ASP.NET page by doing
string userId = null;
if (this.Context.User.Identity.IsAuthenticated)
{
userId = this.Context.User.Identity.Name;
}

As I understand you use ASP.NET authentication and to set cookies persistent you need to set FormsAuthenticationTicket.IsPersistent = true
It is the main idea.
bool isPersisted = true;
var authTicket = new FormsAuthenticationTicket(
1,
user_name,
DateTime.Now,
DateTime.Now.AddYears(1),//Expiration (you can set it to 1 year)
isPersisted,//THIS IS THE MAIN FLAG
addition_data);
HttpCookie authCookie = new HttpCookie(FormsAuthentication.FormsCookieName, authTicket );
if (isPersisted)
authCookie.Expires = authTicket.Expiration;
HttpContext.Current.Response.Cookies.Add(authCookie);

You need to add this as the last line...
HttpContext.Current.Response.Cookies.Add(userid);
When you need to read the value of the cookie, you'd use a method similar to this:
string cookieUserID= String.Empty;
try
{
if (HttpContext.Current.Request.Cookies["userid"] != null)
{
cookieUserID = HttpContext.Current.Request.Cookies["userid"];
}
}
catch (Exception ex)
{
//handle error
}
return cookieUserID;

//add cookie
var panelIdCookie = new HttpCookie("panelIdCookie");
panelIdCookie.Values.Add("panelId", panelId.ToString(CultureInfo.InvariantCulture));
panelIdCookie.Expires = DateTime.Now.AddMonths(2);
Response.Cookies.Add(panelIdCookie);
//read cookie
var httpCookie = Request.Cookies["panelIdCookie"];
if (httpCookie != null)
{
panelId = Convert.ToInt32(httpCookie["panelId"]);
}

Related

Accessing a Generic handler (.ashx) via Https protocol through AJAX from a page which is in Http protocol leads to unsuccessful login

we have a site in which few pages travels in https and few in http and we have implemented a Generic http handler(ashx) for login and auth.
We are using Forms authentication in our site and manually setting Auth cookie in Handler
We have set the access-control-allow-origin to support the mixed of http and https
For security needs we tried to access the handler in https protocol and facing the below issue
When the handler (https) is getting called through AJAX from the secure page (https) everything is working fine
But when the same handler (https) is getting called thorugh AJAX from the non secure page (http) it is not working as in previous case.
In the AJAX success call we are just refreshing the page in javascript.
In 1st case the user name is coming
In 2nd case the same login link will be there.
I am not sure of what is the problem here ? and don't know where to look out ?
Kindly help me out
Thanks
public void ProcessRequest (HttpContext context)
{
string Message = "";
try
{
string EmailId = HttpContext.Current.Request["emailid"].ToString();
string Password = HttpContext.Current.Request["Password"].ToString();
string User = "";
Entities.UserTable user = null;
UserDAL userDAL = new UserDAL();
user = userDAL.UserLogin(EmailId, Password);
if (user != null)
{
int userId = user.Id;
string roles = "User";
bool rememberUserName = true;
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
1, // Ticket version
user.Id.ToString(),// Username to be associated with this ticket
DateTime.Now, // Date/time ticket was issued
DateTime.Now.AddYears(20), // Date and time the cookie will expire
rememberUserName, // if user has chcked rememebr me then create persistent cookie
roles, // store the user data, in this case roles of the user
FormsAuthentication.FormsCookiePath); // Cookie path specified in the web.config file in <Forms> tag if any.
string hashCookies = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, hashCookies); // Hashed ticket
cookie.Expires = DateTime.Now.AddYears(20);
HttpContext.Current.Response.Cookies.Add(cookie);
Message = "success";
}
else
{
Message = "Please check your Mailid or password.";
}
}
catch(Exception ex)
{
Message = "Please contact Support";
}
context.Response.ContentType = "text/plain";
context.Response.Write(Message);
}

Asp.Net - How to expire Cookie

Tried
if (Request.Cookies["IsGuest"] != null)
{
Response.Cookies["IsGuest"].Expires = DateTime.Now.AddDays(-1);
//HttpCookie myCookie = new HttpCookie("IsGuest");
//myCookie.Expires = DateTime.Now.AddDays(-1d);
//Response.Cookies.Add(myCookie);
}
string a = Request.Cookies["IsGuest"].Value;
and also tried by commenting uncommented code and uncommenting commented code but
string a = Request.Cookies["IsGuest"].Value;
Always running and Request.Cookies["IsGuest"] is never null
You got the right concept for deleting a cookie programmatically:
HttpCookie myCookie = new HttpCookie("IsGuest");
cookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(cookie);
However, you missed one point. The above change won't be effective until the postback completes and subsequently user initiates a new request.
MSDN says:
The next time a user makes a request to a page within the domain or path that set the cookie, the browser will determine that the cookie has expired and remove it.
So, the below code illustrates more here::
protected void DeleteCookie_ButtonClick(object sender, EventArgs e)
{
if (Request.Cookies["IsGuest"] != null)
{
HttpCookie myCookie = new HttpCookie("IsGuest");
myCookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(myCookie);
}
// this will always be true here as the Request i.e HttpRequest isn't
// modified actually as the postback isn't complete and we are accessing
// the Cookies collection of same request (not a new request)
if (Request.Cookies["IsGuest"] != null)
{
Label1.Text = "Cookie Collection can't be modified without
making a new request";
}
}
// suppose after postback completes,
// user clicks a button to check the cookie,
// which in turn is a new request/postback/....
protected void CheckCookie_ButtonClick(object sender, EventArgs e)
{
if (Request.Cookies["IsGuest"] != null)
{
Label1.Text = "Cookie is present!";
}
else
{
Label1.Text = "No Cookie is present!";
}
}
One last Note::
Calling the Remove method of the Cookies collection removes the cookie on the server side, so the cookie will not be sent to the client. However, the method does not remove the cookie from the client if it already exists there.
How to Expire a Cookie (on the Client)
I would not reply on ASP.NET Core to remove or expire cookies, as the server-side has very little to do with what happens on the browser. The ASP.NET application & server also has no knowledge of the names of every outdated-cookie, which paths were assigned, if some have already expired, which cookie names are no longer used from an older website, which ones were renamed, which ones are session cookies that need to remain, etc etc.
Cookies are best controlled on the client, which means running JavaScript (unfortunately).
To do that, I recommend you roll your own cookie expiration routine. Below is one I use that removes the top root-path cookies and a sub-path of cookies under the root, starting at the folder from which the script is called from. This generally means most of your cookies are removed. There are some exotic rules as to how browsers remove expired cookies under subpaths that I wont get into. In some cases some subpaths may be missed. But in general, root cookies would all be expired, and any cookies with the same scipts web path and all subpath under it, also expired.
The script below only sets expiration dates on cookies with paths matching the above rules. But the browsers are design to expire cookies under the subpath above as well. Please test in various browser, however, and customize the script as you like. This will NOT delete sessions stored as cookies!
// Get all cookies for this domain but by name-value pairs:
alert('What cookies do I have (name-value)?\r\n ' + document.cookie);
// Get all cookies
var allcookies = document.cookie;
// Splits into multiple cookies
var cookiesArray = allcookies.split(";");
// Loop through each found cookie...
if (cookiesArray && cookiesArray.length >= 0){
for (var i = 0; i < cookiesArray.length; i++) {
var nameString = "";
var pathString = "";
var expiresString = "";
// Strip out all whitespace or formatting from the name-value pair...
var cookieCleaned = cookiesArray[i].replace(/^\s+|\s+$/gm, '').replace(/[\t\n\r]/gm, '')
namePair = cookiesArray[i].split("=");
nameString = namePair[0] + "=; ";// empty the name's value
const earlydate = new Date(0).toUTCString();
expiresString = "expires=" + earlydate;
// DELETE COOKIES using ROOT PATH and SUBPATH
if (namePair[0] !== ""){
// Reset the cookie subpath with new expiration date
// to force the browser cache to delete it.
var pathname = location.pathname.replace(/\/$/,'');
if (pathname !== '') {
pathname = "path=" + pathname + "; ";
document.cookie = nameString + pathname + expiresString;
alert('Final Cookie1:\r\n ' + nameString + pathname + expiresString);
}
// Reset the cookie rootpath, same as above.
document.cookie = nameString + "path=/; " + expiresString;
alert('Final Cookie2:\r\n ' + nameString + "path=/; " + expiresString);
}
}
}
Better you can remove cookie from your list

Persisting Session to DB

My architect is wondering why we need to persist each user's session to the DB instead of just using cookies. I have never seen anyone use just cookies.
Usually I hold the Session Id in a cookie then use it to perform CRUDS on the session record keyed off the ID.
I mean I don't see how you can do session state without in proc. I've always done session state via a custom table holding routine fields like IsLoggedIn, IsClosed, IsNew, IPAddress, Browser, and so on.
Has anyone done session state on an e-commerce site without persisting it in a DB?
UPDATED
So here is kinda how we did things at another place I worked for an e-commerce site that got 500+ page hits a month:
public USession CreateNewSession(int userID)
{
string ipAddress = GetCurrentRequestIPAddress(context.Request);
USession newSession = USession.NewSession();
newSession.IpAddress = ipAddress;
newSession.UserID = customerID;
newSession.Browser = context.Request.UserAgent ?? string.Empty;
if (context.Request.UrlReferrer != null)
newSession.Referer = context.Request.UrlReferrer.ToString();
else
newSession.Referer = string.Empty;
InsertSession(newSession);
return newSession;
}
public USession CreateNewSession(int userID)
{
string ipAddress = GetCurrentRequestIPAddress(context.Request);
USession newSession = USession.NewSession();
newSession.IpAddress = ipAddress;
newSession.UserID = customerID;
newSession.Browser = context.Request.UserAgent ?? string.Empty;
if (context.Request.UrlReferrer != null)
newSession.Referer = context.Request.UrlReferrer.ToString();
else
newSession.Referer = string.Empty;
InsertSession(newSession);
return newSession;
}
public USession GetSession()
{
// existing sessionId this session?
HttpCookie cookie = context.Request.Cookies["usessionId"];
if (cookie == null || string.IsNullOrEmpty(cookie.Value))
session = CreateNewSession(0);
else
{
string sessionID = cookie.Value;
session = GetSession(sessionID);
if (session == null)
session = CreateNewSession(0);
else if (session.IsClosed > 0)
session = CreateNewSession(session.UserID);
}
if (session.LastAccessed < DateTime.Now.AddHours(-1)) session.LoggedIn = false;
if (session.LastDestination.Equals("lesson"))
session.LastDestPageDestinationID = ContextValue(context, "lessonid");
else
session.LastDestPageDestinationID = 0;
if (session.IsNew) session.FirstDestination = session.LastDestination;
SaveSession();
return session;
}
private void SaveSession()
{
session.LastAccess = DateTime.Now;
session.LastDest = string.Empty;
db.UpdateSession(session);
if (!cookieIsSet)
{
// add a session cookie for this current session
HttpCookie cookie = CreateSessionCookie("usessionId", session.SessionID, 365);
if (session.LastDest.Equals("logout", StringComparison.OrdinalIgnoreCase))
cookie.Value = string.Empty;
if (session.LastDest.Equals("lessonOrder")) return;
context.Response.SetCookie(cookie);
}
}
internal void UpdateSession(USession s)
{
using (ourConnection conn = CreateConnection("UpdateSession"))
{
conn.CommandText = #"update csession set
closed = #closed,
userID = #customerID,
lastAccess = #lastAccess,
lastDestination = #lastDest,
orderId = #OrderId,
IsloggedIn = #isLoggedIn;
conn.AddParam("#id", s.Id);
conn.AddParam("#closed", s.Closed);
conn.AddParam("#userID", s.UserID);
conn.AddParam("#lastAccess", s.LastAccess);
conn.AddParam("#firstDestination", s.FirstDestination);
conn.AddParam("#lastDestination", s.LastDestination);
conn.AddParam("#isLoggedIn", s.IsLoggedIn);
conn.AddParam("#orderID", s.OrderID);
try
{
conn.ExecuteNonQuery();
}
catch (Exception ex)
{
LogException(ex);
}
}
}
public HttpCookie CreateSessionCookie(string cookieValue, string uSessionID, double daysTillExpiration)
{
HttpCookie cookie = new HttpCookie("usessionid", uSessionID);
cookie.Expires = DateTime.Now.AddDays(daysTillExpiration);
cookie.Path = "/";
return cookie;
}
So we'd work with the USession custom object in memory throughout our code for checking for loggedIn, to force close their session, and all sorts of stuff based on their current session.
Also in our Application_Error in global.asax we would log the current sessionId for tracking purposes on error.
HttpCookie cookie = Request.Cookies["usessionid"];
if (cookie != null)
{
logger.Variables = "<b>uSessionID:</b> " + cookie.Value;
if (cookie.Value.Length > 0)
logger.USessionID = GetUSessionID(cookie.Value);
}
The ASP.NET session has 3 possible states:
Off (my preferred) - don't use any session at all
InProc - the session is stored in the memory of the web server. Fast, but not convinient if you are running in a web farm because each node of the web farm will have a different copy of the session and you might get conflicts.
Out-of-Proc - the session is stored in memory of a specially dedicated server running the ASP.NET Session state Windows service. Good for webfarms scenarios but not reliable enough as the session is still persisted in the memory of some server which might not survive crashes.
SQL Server - the session is persisted in SQL server. Very reliable and suitable for web farms. Problem is with performance. It will be slower than the previous modes as the session is now persisted in the database.
The 3 modes are covered in depth in the following article.
The mode you choose is configured in web.config and it is completely transparent to your code in which you simply use the Session["someKey"] to work with the session, it's just the underlying storage mechanism that differs.

IsAuthenticated works on browser - but not with Air client!

My login code, after authentication:
var authTicket = new FormsAuthenticationTicket(
1,
userName,
DateTime.Now,
DateTime.Now.AddMinutes(20), // expiry
false,
roles,
"/");
var cookie = new HttpCookie(FormsAuthentication.FormsCookieName, FormsAuthentication.Encrypt(authTicket));
Response.Cookies.Add(cookie);
and, thanks to Darin Dimitrov, I have a custom Authorize attribute:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, Inherited = true, AllowMultiple = true)]
public class TJAuthorize : AuthorizeAttribute {
public override void OnAuthorization(AuthorizationContext filterContext) {
string cookieName = FormsAuthentication.FormsCookieName;
if (!filterContext.HttpContext.User.Identity.IsAuthenticated ||
filterContext.HttpContext.Request.Cookies == null || filterContext.HttpContext.Request.Cookies[cookieName] == null) {
HandleUnauthorizedRequest(filterContext);
return;
}
var authCookie = filterContext.HttpContext.Request.Cookies[cookieName];
var authTicket = FormsAuthentication.Decrypt(authCookie.Value);
string[] roles = authTicket.UserData.Split(',');
var userIdentity = new GenericIdentity(authTicket.Name);
var userPrincipal = new GenericPrincipal(userIdentity, roles);
filterContext.HttpContext.User = userPrincipal;
base.OnAuthorization(filterContext);
}
This all works beautifully when I'm working in a browser session. But now I am working with a Flash/Adobe Air client, and the authentication attribute is causing a failure. By putting debug statements into the code, I can tell that:
filterContext.HttpContext.User.Identity.IsAuthenticated
is false - even after a successful login!
Why should there be any difference between using a browser client and an Air client? And how do I fix this?
EDIT: Another clue: after putting in some more debug statements, I have found that the filterContext.HttpContext.User.Identity is not correctly set when making the call from Air - the Name property comes out blank! Session ID is correct, cookie ID is correct - but the User.Identity is not set. Any ideas why this might be happening?
Perhaps HttpCookieMode (http://msdn.microsoft.com/en-us/library/system.web.httpcookiemode.aspx) is set to the wrong value?
Default is UseDeviceProfile ... what happens when you force it to UseCookies ?
It's a longshot, but IsAuthenticated depends on client's ASPXAUTH cookie (or whatever you've named id) being sent with request. Make sure that flash/air is sending that cookie (by wireshark or any other network tool)
Does the HttpContext.User.Identity show up in the Application_AuthorizeRequest in global.asax?

FormsAuthentication - handling a change of username

My ASP.NET MVC web application allows administrators to change their own, or other users' usernames.
Users are logged in by calling FormsAuthentication.SetAuthCookie(userName [string], createPersistentCookie [bool]). They are logged out by calling FormsAuthentication.SignOut(). I understand that after updating the username I'd need to sign them out and back in again. But how do I retrieve the existing value of createPersistentCookie? e.g. how do I retain their original 'remember me' setting when signing them back in?
var cookieName = FormsAuthentication.FormsCookieName;
var request = HttpContext.Current.Request;
var cookie = request.Cookies.Get(cookieName);
if (cookie == null)
return;
try
{
var ticket = FormsAuthentication.Decrypt(cookie.Value);
//This should give you what you want...
bool isPersistent = ticket.IsPersistent;
}
catch (Exception ex)
{
//Logging
}

Resources