I have been searching the web and found many odd answers and i've tried almost all of them.
My problem is this. My login page contains:
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(min), persistCookie, userid.ToString());
string encTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = ticket.Expiration;
Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage(userName, persistCookie);
Now the min value is per user based and can be set individually, so is persistCookie.
After what i understand this code should result in the possibillity of overriding the default values in web.config. Which should be 30 minutes.
<authentication mode="Forms">
<forms loginUrl="~/Default/default.aspx" defaultUrl="~/User/UserMain.aspx"/>
</authentication>
min is currenlty set to 120, and persistCookie is set too true. When i log in i get timeout at 30 minutes. (Not session, so somewhere expiration date is set, because if it was not set the cookie should be session based, also i do not get 120 minutes which is kind of the deal here)
My question, for simplifying it, is how do i get the value 'min' to be the expiry date of the cookie?
This might turn out too be a simple thing but i am currently totally stuck so any help would be appriciated.
EDIT:
I changed the login logic to this:
FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, userName, DateTime.Now, DateTime.Now.AddMinutes(min), persistCookie, userid.ToString());
string encTicket = FormsAuthentication.Encrypt(fat);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = fat.Expiration });
Response.Redirect(FormsAuthentication.GetRedirectUrl(userName, false));
And now it works. But i cant seem to figure out why this would work, and not the previous one.
Ticket creation is the same, the only difference is that i add Expires property of the HttpCookie when creating the HttpCookie, not after the object is made.
If anybody has a good explanation i am all ears! :)
The problem with your code is that you're calling RedirectFromLoginPage, which will create the forms authentication cookie, overwriting the cookie you've just created:
HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encTicket);
cookie.Expires = ticket.Expiration;
Response.Cookies.Add(cookie);
FormsAuthentication.RedirectFromLoginPage(userName, persistCookie); <-- creates a new cookie
The cookie created by RedirectFromLoginPage will of course have the default timeout taken from configuration.
Your second version is the way to go.
I think you don't understand the difference between cookie expiration and ticket expiration dates - ticket can be considered as expired even if the cookie it is being stored in is still valid. The 4th param of FormsAuthenticationTicket constructor is responsible for the ticket expiration date.
So, to answer your question, you need to manually set expiration date of your cookie or make it long enough to exceed expiration date of your authentication ticket.
Related
I'm setting a cookie like so:
protected void SetCookie(bool value, int expiration)
{
var cookie = Response.Cookies[COOKIE_NAME] ?? new HttpCookie(COOKIE_NAME);
cookie.Value = value.ToString();
cookie.Expires = DateTime.UtcNow.AddDays(expiration);
Response.Cookies.Set(cookie);
}
In the SetCookie function, when I inspect the cookie on the last line, the Expiration is set to tomorrow's date.
However, when I retrieve this cookie on the next page load:
var cookie = Request.Cookies[COOKIE_NAME];
the cookie exists, but the expiration date is the default date value of 1/1/0001 12:00:00 AM
I believe the expiration is a client-side thing. The browser should send any not-expired cookies, but does not send the expiration date (only name and value). I think you should re-set and refresh the expiration on each request.
This was the first format reference I found: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie
If for whatever reason you need to retrieve the expiration data server side, I would include it in the cookie contents or set a secondary cookie to contain that information.
I am creating a website, and I'm not sure how to use sessions with cookies.
When sessions timeout, I want to show the username and time of the user; for e.g., username stored in cookies and session. When sessions timeout the username must be retrived from the cookies.
Lets put things in perspective first.
A session is the session a user is experiencing when he is using the website.
How it works is basically a user starts a session with the web server, the web server then gives it a key of the session and sets a timeout for the session which are stored as a cookie.
Since this process is automatic and you can only configure it in web.config (unless you are asp.net core vNext, which I doubt) with sessionState https://msdn.microsoft.com/en-us/library/h6bb9cz9%28v=vs.80%29.aspx
A normal HttpCookie on another hand is something you set on your Response object and can give it a specific expiration date like this:
HttpCookie myCookie = new HttpCookie("MyTestCookie");
DateTime now = DateTime.Now;
// Set the cookie value.
myCookie.Value = now.ToString();
// Set the cookie expiration date.
myCookie.Expires = now.AddMinutes(1);
// Add the cookie.
Response.Cookies.Add(myCookie);
Which suits your needs more likely.
If you want more information about sessions expiration I'd also suggest you check out http://www.hanselman.com/blog/TroubleshootingExpiredASPNETSessionStateAndYourOptions.aspx
I want to add a "keep me logged in" option to my custom login control.
This is how I'm currently using the session:
I'm saving and reading values from HttpContext.Current.Session["key"] manually. Works fine.
Relevant parts of web.config:
<sessionState mode="StateServer" useHostingIdentity="true" cookieless="false" timeout="120" stateConnectionString="tcpip=127.0.0.1:42424" />
<authentication mode="Forms">
<forms loginUrl="/login" name="AuthCookie" timeout="120" slidingExpiration="true" path="/" />
</authentication>
<authorization>
<allow users="*" />
</authorization>
As you can see, the default duration of a session is 120 minutes.
"Logout":
Session.Clear();
Session.Abandon();
Through a custom login control with textboxes, I grant access to a member area. (I don't use System.Web.Security.FormsAuthentication)
After entering valid credentials and a checked checkbox "keep logged in", I want to increase the duration of the already active session to ~30 days.
So far I've found solutions like
FormsAuthenticationTicket fat = new FormsAuthenticationTicket(1, "username", DateTime.Now, DateTime.Now.AddMinutes(1), false, "username");
string encTicket = FormsAuthentication.Encrypt(fat);
Response.Cookies.Add(new HttpCookie(FormsAuthentication.FormsCookieName, encTicket) { Expires = fat.Expiration });
which don't work, because System.Web.Security.FormsAuthentication.Timeout is still at 120 minutes.
The same goes for setting
Session.Timeout = 666;
Any suggestions?
You can't really approach it this way. You can't persist a session over days - it's just not going to scale well.
What most people do is provide a means for automatic login, so that when their session expires, they are seamlessly logged back in on the next action/reload. Most people do this with a cookie that contains a unique hash, which is checked at the server. If you want the person to be logged in for 30 days, you just set the cookie to expire in 30 days time.
I decided to give a short summary how I ended up doing it, because #David Haney asked me to:
I added a column to my usertable, which contains a GUID that is used for "relogging in" / giving credentials again. That GUID is created upon login and stored in the database.
It's also stored as an ecrypted value in a cookie. (My site doesn't use SSL)
Added to Login routine (if a user checked the "remeber me" checkbox):
HttpCookie aCookie = new HttpCookie("Session");
Guid sessionGuid = // Buisiness layer call to generate value
String sessionID = sessionGuid.ToString();
aCookie.Value = Helper.Protect(sessionID, "sessionID");
aCookie.Expires = DateTime.Now.AddDays(30);
Response.Cookies.Add(aCookie);
where Helper.Protect and Helper.Unprotect are used from here How to use MachineKey.Protect for a cookie? to store an encrypted and MAC signed value in a cookie.
Relogging is done by having every content page inherit from a class, that implements that logic and inherits from System.Web.UI.Page.
public class BasePage : System.Web.UI.Page
{
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
if (Request.Cookies["Session"] != null && !CustomIsLoggedInCheckMethod)
{
String unprotected = Helper.Unprotect(Request.Cookies["Session"].Value, "sessionID");
Guid sessionID = Guid.Parse(unprotected);
// Calls to buisiness layer to get the user, set sessions values et cetera
}
}
}
If a user was banned after the last session or logs out, the cookie value expiration date will be set to a date in the past:
HttpCookie myCookie = new HttpCookie("Session");
myCookie.Expires = DateTime.Now.AddDays(-1d);
Response.Cookies.Add(myCookie);
Edit:
Ah I forgot to mention this. I've also added a notification bar, that tells the user that he has been logged back in. It's based on http://blog.grio.com/2012/11/a-copypaste-ble-jquery-notification-bar.html
See Demo
I'm trying to implement a login form with the remember me functionality in ASP.NET 4.0.
I've set the timeout option in the web.config to 1 year (525600), but after a random amount of time after I logon, I always get logged off.
The cookie is created correctly, I can see it in the browser with the right expire value (september 2014), but it seems that this cookie after some time is not readed by the ASP.NET environment anymore.
I tryed to login with:
FormsAuthentication.RedirectFromLoginPage(username, true);
or:
FormsAuthentication.SetAuthCookie(username, true);
Response.Redirect("/");
or with this custom code:
DateTime expiryDate = DateTime.Now.AddMinutes(FormsAuthentication.Timeout.TotalMinutes);
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(2, userid, DateTime.Now, expiryDate, true, String.Empty);
string encryptedTicket = FormsAuthentication.Encrypt(ticket);
HttpCookie authenticationCookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
authenticationCookie.Expires = ticket.Expiration;
Response.Cookies.Remove(FormsAuthentication.FormsCookieName);
Response.Cookies.Add(authenticationCookie);
Response.Redirect(FormsAuthentication.GetRedirectUrl(username, false));
But the result is always the same. The cookie is present, but after some time it's not used anymore.
The Web.config is like so:
<authentication mode="Forms">
<forms loginUrl="/login" defaultUrl="/" name="appName" path="/" timeout="525600" slidingExpiration="true"/>
</authentication>
The odd thing is that in my local test environment (ASP.NET Development server) things works correctly. Only in the production environment it is not working!
#Felipe Garcia: I don't know if I'm using a load balancer, I'm on a public server. But I tryed to config the MachineKey as you said (using the generator here) and now it seems to work correctly!
Thank you!
So there are lots of posts on StackOverflow regarding this, but I still was unable to solve my exact problem. Here's the gist:
I have a website that requires authentication. I am using the standard .NET FormsAuthentication.SetAuthCookie() method to persist the user's session.
My question is this: In the web.config file, there is a timeout attribute to the "/system.web/authentication/forms" node. If I set this value to say, 30 minutes, is this the time of user inactivity the user can have before their session expires?
The reason I ask is that no matter what I set this value to, if I set persistence to true in SetAuthCookie(), the expiration on the cookie set is 90 minutes. If I set persistence to false in SetAuthCookie(), the cookie expiration is set to "end of session".
What is that "Timeout" attribute value actually setting, and how can I get a persistent cookie that lasts a month or a year or longer?
The parameter timeout you've found in /system.web/authentication/forms is the timeout (in minutes) of the duration of authentication ticket.
This means that after a certain amount of time of inactivity, a user is prompted to login again. If you try to check this My.Profile.Current.IsAuthenticated it will be false.
You can choose not to persist the cookie. In this situation if your ticket expires, your cookie expires too. The cookie (in case is persisted) has a purpose to remember the user if he/she comes back to your site.
You might want to persist your cookie for 10 years so the user will never have to insert username and password again, unless they've chosen to delete the cookie. The cookie is valid even if the browser is closed (when it is persisted).
Another important thing to remember is the parameter slidingExpiration:
<authentication mode="Forms">
<forms loginUrl="~/Partner/LogOn" defaultUrl="~/Home/Index"
timeout="30" slidingExpiration="true" />
</authentication>
if it's true your authentication ticket will be renewed every time there's activity on your site: refresh of the page etc.
What you can do - and what I've done - is to write your own cookie like this:
FormsAuthenticationTicket authTicket = new
FormsAuthenticationTicket(1, //version
userName, // user name
DateTime.Now, //creation
DateTime.Now.AddMinutes(30), //Expiration (you can set it to 1 month
true, //Persistent
userData); // additional informations
Update
I've implemented this routine cause I want to store my groups in an encrypted cookie:
Dim authTicket As System.Web.Security.FormsAuthenticationTicket = _
New System.Web.Security.FormsAuthenticationTicket( _
1, _
UserName, _
Now, _
Now.AddYears(100), _
createPersistentCookie, _
UserData)
Dim encryptedTicket As String = System.Web.Security.FormsAuthentication.Encrypt(authTicket)
Dim authCookie As HttpCookie = New HttpCookie( _
System.Web.Security.FormsAuthentication.FormsCookieName, _
encryptedTicket)
If (createPersistentCookie) Then
authCookie.Expires = authTicket.Expiration
End If
Response.Cookies.Add(authCookie)
As you can see I've set the expiration of the authentication cookie and the authentication ticket with the same timeout (only when persisted).
Another thing that I've tried is to stored username and password in the encrypted cookie.
Everytime a masterpage is loaded I check My.Profile.Current.IsAuthenticated to see if the authentication is still valid. If not I read the cookie again, get the username and password, and check it on the DB:
Public Function ReadCookieAuthentication(ByVal Context As System.Web.HttpContext) As Security.CookieAuth
Dim CookieUserData = New Security.CookieAuth()
Dim cookieName As String = System.Web.Security.FormsAuthentication.FormsCookieName
Dim authCookie As HttpCookie = Context.Request.Cookies(cookieName)
If (Not (authCookie Is Nothing)) Then
Dim authTicket As System.Web.Security.FormsAuthenticationTicket = Nothing
Try
authTicket = System.Web.Security.FormsAuthentication.Decrypt(authCookie.Value)
If (Not (authTicket Is Nothing)) Then
If (authTicket.UserData IsNot Nothing) AndAlso Not String.IsNullOrEmpty(authTicket.UserData) Then
CookieUserData = New JavaScriptSerializer().Deserialize(Of Security.CookieAuth)(authTicket.UserData.ToString)
End If
CookieUserData.UserName = authTicket.Name
End If
Catch ex As Exception
' Do nothing.
End Try
End If
Return (CookieUserData)
End Function
Security.CookieAuth is an object I've created to return username and password.
CookieUserData is the storage (I save in json format) where I put my password and groups.