Virtual Users, custom properties and persisting data
I’ve seen a few questions recently regarding Virtual Users within Sitecore and asking how their data is persisted (if it is at all), so I thought I’d try to clear up any confusion around this.
What are virtual users?
A Virtual User within Sitecore is a transient entity used to represent an authenticated user on your site, unlike a regular user that is persisted within the Sitecore Core database (by default!). A common use-case for this scenario would be if you are using an external system for authentication. A Virtual User allows you to create an authenticated session for that user, without needing to create them in Sitecore. They don’t get fully persisted, and you won’t see them in the User Mananger. However, Sitecore treats them like any other user when it comes to roles + access rules. You’re even able to specify custom properties for virtual users.
Logging in a Virtual User is very straightforward. Here is a typical example for creating a new Virtual User and setting some roles + properties:
|
|
After the LoginVirtualUser
is called, an authenticated session is established and on future page requests, the Sitecore.Context.User
will be extranet\[email protected]
.
How is the user authenticated?
A Virtual User is often referred to as an “in-memory” user, suggesting that the user data is held within memory and won’t survive a server restart. This isn’t really true, as we’ll see.
If you are using Forms Authentication, when the LoginVirtualUser
method is called, a standard Forms Authentication cookie is created. By default, this has the name .ASPXAUTH
, and will have an encrypted value such as this:
|
|
During an HTTP request, this data is decrypted into a FormsAuthenticationTicket
. In this demo instance, it contains the following data:
|
|
This ticket alone is enough for Sitecore to consider the user authenticated as the specified user and allow access to any pages you may have set as restricted to anonymous users.
What about roles and properties?
In the above code example, we added the virtual user into the extranet\CustomRole
role and also added some profile properties. As you can see, this information isn’t found within the ticket. So where is it? Well, note that there is a UserData
property which contains a string, cj5qfethsr0z4ej1xjxkh4ox
. That’s important.
If I take a look at the Core
database for this instance, I find the following row in the ClientData
table:
The value of SessionKey
field refers to both the current ASP.NET Session ID and also the UserData
value from the authentication ticket. The Data
field is a Base64 encoding of a serialized Hashtable
object. Within that, is a serialized instance of a Sitecore.SecurityModel.UserRuntimeSetings
object that contains all of the Virtual User data, such as the roles they belong to, and their custom properties.
So as you can see, data is persisted for the Virtual User. Additionally, as the cookie is persisted on the user’s machine, the authenticated user and their data will survive a restart of the web process / server. If you have multiple load-balanced servers referencing the same Core
database, then the Virtual User data will be available to each server, avoiding any load-balancing issues in this particular scenario.
It’s worth noting that this data survives if the ASP.NET Session ID is abandoned. In this instance, the session cookie is removed, but the authentication cookie remains. As this authentication cookie still retains the key within the UserData
property, the data can still be pulled out of the Core
database.
ClientData compacting
You should note that the ClientData
table does get cleaned up on a regular basis. There is an agent responsible for this, and that executes every 4 hours by default:
|
|
This uses a parameter of the ClientData configuration to determine the object lifetime
, which defaults to 20 minutes. Any rows which have not been accessed within that time in the table will be removed when the agent executes:
|
|
So, without changes to this, you shouldn’t treat this storage of Virtual User data as a permenant. But then, it’s not intended to be - generally this would be storage of data you’re only interested in keeping for the duration of the user’s session. If you need something more than this you should look into an alternate method.
So… ClientData? Is that new?
The ClientData table has actually been within the Sitecore database for quite some time now, but the use of it to persist Virtual User information is relatively recent. In fact, it was introduced in Sitecore 8.1 rev. 160302 (8.1 Update-2)
.
So what happened before then? Well, in earlier versions of Sitecore, the user profile data was actually stored entirely within the authentication cookie:
|
|
So, prior to Sitecore 8.1 Update 2, there was no dependency on the Core
database for storing Virtual User profile data. As long as the cookie is in place, the Virtual User would be correctly restored.
Further information
That’s what I’ve found from my short dive into Virtual User operations. If you think I’ve stated anything inaccurate, please let me know! I’m going to be looking at this further and into any other common questions around Virtual Users that I see, so if needed I’ll provide a follow-up post with more detail.