We use a DistributedSqlServerCache to store user session data but I have noticed some unexpected/strange behaviour. So I was wondering how a DistributedSqlServerCache works under the hood to help me understand the behaviour that I am seeing.
When a user arrives at the site, immediately a DB entry is inserted, as seen below in img 1.
When the user logs out or the session times out, the session data is cleared (replaced with some arbitrary default value) and the ExpiresAtTime is also reset, as seen below in img 2.
Again, another user arrives at the site, and a new DB entry is inserted, as seen below in img 3.
But this time, if the application pool is recycled or the IIS is reset, then the below (img 4) is the result in the database:
It appears that the original session has not been emptied and also a new session is started.
For completeness, here's the code we use in StartUp.cs:
services.AddDistributedSqlServerCache(o =>
{
o.ConnectionString = "conn_string...";
o.SchemaName = "dbo";
o.TableName = "PS_PWD_SESSIONS";
});
services.AddSession();
Unless I’ve got the wrong end of the stick, this doesn’t make sense to me. I would be very grateful for any insight into this behaviour.
It's best not to worry about this too much. ASP.NET Core knows what it's doing. I think the behavior you're seeing is a result of session key vs. session id. The session id is tied to the actual physical session, persisted in the database here. However, the cookie that gets sent to the user contains only a session key. This session key is always valid and never expires. The client then always sends back this cookie with the same session key, and ASP.NET Core internally decides whether to restore the previous session or create a new one, based on whether the session has expired, etc.
In other words, the underlying data in the actual database doesn't necessarily reflect existing "sessions", at least from a client perspective. To the client, their session lives forever, but in the database it could be deleted. If there's no active session in the database to correspond with the client's session key, then ASP.NET Core just creates a new one.
Related
I am using Identity Server 4 with the quickstart UI and a client using Cookie Authentication.
Lets say I have user A on machine A who is currently logged in via the browser. Then user A decides to go on machine B and logs into that one. As it stands, a new session cookie will be issued for user A on machine B as well as machine A.
This is fine, but I want the option to mark particular users with a flag e.g. IsConcurrent and if it is set to true, they will be given the option to either keep their existing session on machine A, or terminate it and start a new session on machine B.
I have done some reading and found references here to updating the security stamp for a user and setting the interval to zero, so it checks the security stamp in the cookie against the stored version. However, this code didn't seem to be inline with Identity Server's code. Also, it it a valid option in this case?
I also found here which mentions storing and checking the value of session IDs, but I'm not sure if this is valid either?
An initial idea was to implement some middleware that obtained the Machine ID and stored it in a table along with the user, but then I was unsure how to take something like this any further.
Any help or advice would be much appreciated.
Assuming cookie based authentication, you can extend the client to validate the user session provided that the client keeps track of user sessions.
For that you can create a session manager where you add a session for the user (sub) after login, this also includes automatic login sessions (SSO). Remove one or all sessions on logout, which should also be updated on back channel logout (LogoutCallback).
Assuming you use middleware, you can consult the session manager there and decide what to do. Make sure that the current session isn't already activated after login. It has to step through the middleware at least once. Some pseudo code to illustrate the idea:
public Task Invoke(HttpContext context, SessionManager sessionManager)
{
if (context.Principal.Identity.IsAuthenticated)
{
var sub = context.Principal.FindFirst("sub")?.Value;
var sid = context.Principal.FindFirst("sid")?.Value;
// User is allowed when the current session is active.
if (!sessionManager.CurrentSessionIsActive(sub, sid))
{
// Rewrite path if user needs and is allowed to choose: redirect to session selector or
// Activate the current session and deactivate other sessions, if any.
if (sessionManager.HasMultipleSessions(sub) && sessionManager.CanSelectSession(sub))
context.Request.Path = new PathString("/SelectSession");
else
sessionManager.ActivateCurrentSession(sub, sid);
}
}
return _next(context);
}
On post of the SelectSession form you can mark in the session manager which sessions are active. If the old session should be preserved, then ignore the old session (remains active) and mark the current session as active.
Make sure to add the middleware after authenticating the user.
Please note that for access tokens you'll need a different strategy.
I'm almost sure what I'm looking for exists, but I didn't finding on Microsoft documentation nor here.
I just want to get an unique ID (a string or a number, I don't really mind) from a client in ASP.NET 4.5, on the server side. I want this ID linked to a session, so different for each system that would connect to my server (like multiple computers or same client with different browsers), but the same if a user open multiple tabs on the same browser on my server.
I already looked on:
System.Web.UI.Page.ClientID: It is the name of the control (so always "__Page").
System.Web.UI.Page.UniqueID: It returns the same.
Session.LCID: I'm not sure to what it refers to, but it is the same if I connect to my server with different browsers.
Session.SessionID: Change each time I refresh the page or open it in a new tab.
Request.AnonymousID: Is null.
So all my attempts gave me an ID that changes everytime or never. Is there any way to get something from session ?
What you are looking for is in fact the Session.SessionID, however it comes with a caveat.
From MSDN:
When using cookie-based session state, ASP.NET does not allocate storage for session data until the Session object is used. As a result, a new session ID is generated for each page request until the session object is accessed. If your application requires a static session ID for the entire session, you can either implement the Session_Start method in the application's Global.asax file and store data in the Session object to fix the session ID, or you can use code in another part of your application to explicitly store data in the Session object.
I suggest using REMOTE_ADDR / REMOTE_HOST values from ServerVariables collection. These would have same values even if the user is using multiple browsers and uses different sessions from the same machine. Note that REMOTE_HOST might not always have a value.
References :
https://msdn.microsoft.com/en-us/library/system.web.httprequest.servervariables(v=vs.110).aspx
https://msdn.microsoft.com/en-us/library/ms524602(v=vs.90).aspx
In my web application I test for a condition on one page and want to retain the results of the test for a specified duration (such as 5 minutes). I can do this with a cookie, of course, but just in case a user has disabled cookies, I'm thinking a custom server varible might do the trick. I've heard about this, but I haven't been able to find out to do it.
Alternatively, maybe a session variable might be better? There's no inherent way to expire these, right? How long would such a variable survive before IIS tosses it?
Asp.Net has session state. Each Asp.Net Page has a Session property. You can also access it via HttpContext.Current.Session, though there is a subtle difference that won't matter until it bites you (which see my answer to the question, Difference between Session and HttpContext.Current.Session.
The default session state configuration is in-memory. That means that if your web site is served up from something like an F5 Networks Big IP (load balancer) cluster, unless the load balancer is set up to be 'sticky' (meaning that once assigned to a machine in the cluster, you'll always hit that machine unless it goes down or is otherwise removed from the cluster).
If your clustered web site doesn't have sticky sessions, your session state will vanish when your request hits a different machine...and then reappear when another request hits the original machine. You can guess how much fun that can be.
There is built-in support for SQL Server session that you can enable in your web.config. Once set up that way, you're using SQL Server as the backing store for session state. That solves the server farm issue noted above, but does so at the expense of hitting a SQL Server each and every time a session state value is accessed. That slows down access considerable, especially if the session size large. Oddly, executing a SQL query and shoving a 500kb session blog across the network every time you access a session state setting can negatively impact performance. Who knew? [Don't ask how we found that out].
There are other solutions to the problem: ScaleOut's products come to mind (e.g., ScaleOut SessionServer).
Or you can roll your own session state provider using something like an AppFabric cache.
Another "feature" of using SQL Server sessions state is that anything going into Session must be ISerializable.
You can't set a server variable; instead, using Session, which is tied to the current user, is the best approach for user-based data. For application-based data, you can consider cache. So assuming the former, do:
Session["Key"] = MyValue
Note that session lasts 20 minutes; if you have to have exactly 5 minutes, you can use cache, which you can explicitly expire at 5 minutes:
Cache.Add(CurrentUserID.ToString() + "Key", "Value", .. TimeSpan.FromMinutes(5));
You can use the ID of the current user to make the cache value specific to a user, or use cookies, but set HttpOnly=True on the cookie object. An HTTPOnly cookie is only on the server and never accessible on the client, as such:
varcookie = New HttpCookie("Key", Value);
cookie.Expires = ..;
cookie.HttpOnly = true;
I've just been given a new task to bootstrap a website created by someone else. But I'm absolutely new to Web. The website is in ASP.NET,C#. The code itself is not hard to understand except for the Session object. I don't understand where, how and why it's used.Could please someone explain the usage of Session object with a possible example?
P.S. What would these two lines mean?
lblPensValue.Text = sh.pensDec((string)Session["connSTR"], 113, 23);
and
if ((string)Session["connSTR"] == null)
Session is used to store data for the user's session on the web site. (this data store is per-user-browser session, and is subject to being wiped at any time by various application events)
It is generally used to store information across multiple page views in a user's session (ie. visit) to your website.
It can be used anywhere in code that runs in the context of the user's session; meaning inside a page, or in the appropriate application lifecycle events which run in the context of a session (such as Session Start)
As for your samples;
The first one, I can't fully explain, as I do not know what the function sh.pensDec() is supposed to do.
The second one is checking to make sure there is a value stored in that session variable, before running the code that follows.
HTTP by nature is stateless. The WebServer doesn't know any details after it processes the request and sends back to the client. Thus, any subsequent requests are like fresh requests to the server.
To Enable the Server to remember & subsequently recognize what it served to the client, ASP.NET uses various mechanisms of which Session is one of them.
Session is created per user. So, in your Page, you are fetching the "connSTR" are storing it. Whenever a subsequent request comes from the same user, by querying Session with the key
Session["connSTR"]
you get back its value. Since Session is an Object, its casted as a string in your code.
(string)Session["connSTR"] // Return value from session and casting to string
You need to understand Session, check this ASP.NET Session State Overview
ASP.NET session state enables you to store and retrieve values for a user as the user navigates ASP.NET pages in a Web application.
ASP.NET Session State Overview
ASP.NET Session State Examples
Look at, e.g.,
ASP.NET Wiki › State Management › Session
ASP.NET Session State Overview
the documentation for the HttpContext.Session Property
You see the code below, how I did use the session variable;
So the three questions are:
Where are they stored? (Server or Client side)
Are they unique for each web page visitor?
Can I remove it using ajax or simple js code when my job is done with it? or it will be removed automatically..?
.
sbyte[][] arrImages = svc.getImagesForFields(new String[] { "CustomerName", "CustomerSurName" });
Dictionary<string, byte[]> smartImageData = new Dictionary<string, byte[]>();
int i = 0;
foreach (sbyte[] bytes in arrImages)
{
smartImageData.Add(fieldNames[i], ConvertToByte(bytes));
i++;
}
Session.Add("SmartImageData", smartImageData);
Read more about sessions here. To answer your questions:
Depends on your configuration (in-process, Session State Server etc.), but always server-side.
Yes, each visitor gets a unique cookie.
You can remove it client-side by removing the session cookie (usually ASP.NET_SessionId), or server-side by calling Session.Abandon(). Also, a session times out after a certain (configurable) period of inactivity.
Session variable are stored on the Server? You can configure other state management mechanism (E.g Database).
They are unique for each user session. It will be removed when Session times out.
Session state information is stored on the server and not on the client side. When the session expires, this session information is removed completely and automatically. You can change the session expiration duration through web.config file. Session data is unique for each user. You can always use it using ajax or change it or even remove it.
If you want the session data persistent to be persistent, you can configure your database for storing the session information. You can even configure a state server to store the session data.
The session is usually stored on the server (depending on your server/application configuration). Each unique browser connection is allocated a session id which the server uses to associate the client with a unique server session on subsequent connections. The session id is passed to the client to store as either a cookie, or as a paramater attached to each url request to the server.
It is used as a means of preserving client state with the server between HTTP calls.
The session expires after a configurable time of inactivity. However in .NET you can call Session.Abandon() to end the current session.