servicestackservicestack-auth

ServiceStack: Several logins from different devices (phone, web etc) - I want one session per device


The problem: it seems to me, like the normal and best way to look at sessions is: One session per device, per user.

So, you can have one session alive per device, meaning one session per web browser, per phone, tablet etc. You should not be allowed have two or more valid sessions for the same phone, for example.

When I implemented my own session cache and auth structure, I implemented it as above, since my apps are sending a "DeviceUUID" that is unique for each device. In that way, I could detect that "there is a valid session for this DeviceUUID and User already" and act accordingly (replace the old session with a new one).

Now, when I am evaluating ServiceStack, I'd like some input on how to do this using the IAuthSession etc.

Currently, I have custom code to authenticate to the backend, so I get a IAuthSession that I populate with some data, like:

                session.FirstName = alrReply.Actor.Firstname;
                session.IsAuthenticated = true;
                session.UserAuthName = alrReply.Actor.Username;
                session.UserAuthId = alrReply.AuthToken;
                session.Roles.Add("alfaconnect");
                base.Request.SaveSession(session);

I also have access to the "DeviceUUID", but I'm not sure how to make sure ServiceStack behaves as described above. Is it doable?

I have read similar posts here in SO, but either they didn't address the same issue, of I didn't understand the answer.


Solution

  • The way I solved the question can be seen below, even though a much more efficient way to check for duplicate sessions for the same DeviceUUID should be implemented.

    1. I am using my own custom login stuff
    2. When I get a successful login, I go through all IAuthSessions and check for other sessions that has the same DeviceUUID and UserId (my custom userId)
    3. I use the IAuthSession AuthProvider to save the DeviceUUID

    if (alrReply.Success) // when my custom code decided login was OK
    {
        ICacheClient cacheClient = TryResolve<ICacheClient>();
        IDictionary<string, IAuthSession> sessionList = cacheClient?.GetAll<IAuthSession>(cacheClient?.GetAllKeys());
    
        foreach (KeyValuePair<string, IAuthSession> kvp in sessionList)
        {
            if (kvp.Value.AuthProvider == deviceUUID && // Found a session from the same Device
                kvp.Value.UserAuthId == alrReply.Actor.Id.ToString()) // for the same user
            {
                // We only allow one session per device and user
                Request.RemoveSession(kvp.Value.Id);
                Console.WriteLine($"Removed duplicate session ({kvp.Value.Id}) for Device {kvp.Value.AuthProvider} for user {kvp.Value.DisplayName}, nbr of sessions was {sessionList.Count}");
            }
        }
    
        session.IsAuthenticated = true;
        session.UserAuthId = alrReply.Actor.Id.ToString();
        session.UserAuthName = alrReply.Actor.Username;
        session.DisplayName = alrReply.Actor.ToString();
        session.AuthProvider = deviceUUID;
    
        session.FirstName = alrReply.Actor.Firstname;
        session.LastName = alrReply.Actor.Lastname;
    
        session.Roles = new List<string>();
        session.Roles.Add("alfapro");
    
        base.Request.SaveSession(session);
        // ... etc