ServiceStack:来自不同设备(phone、网络等)的多个登录 - 我希望每个设备一个会话

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

问题:在我看来,查看会话的正常和最佳方式是:每个用户每个设备一个会话

因此,您可以让每台设备有一个会话有效,这意味着每个网络浏览器、每个 phone、平板电脑等有一个会话。您不应该被允许为同一个 [=29] 有两个或更多有效会话=],例如。

当我实现自己的会话缓存和身份验证结构时,我按照上面的方式实现了它,因为我的应用程序正在发送每个设备唯一的“DeviceUUID”。通过这种方式,我可以检测到“这个 DeviceUUID 和用户已经有一个有效的会话”并采取相应的行动(用新的会话替换旧的会话)。

现在,当我评估 ServiceStack 时,我想要一些关于如何使用 IAuthSession 等来执行此操作的输入。

目前,我有自定义代码来对后端进行身份验证,所以我得到了一个 IAuthSession,我用一些数据填充了它,例如:

                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);

我也可以访问“DeviceUUID”,但我不确定如何确保 ServiceStack 的行为如上所述。可行吗?

我在 SO 中有 read similar 个帖子,但要么他们没有解决相同的问题,要么我不明白答案。

此功能未明确支持,但您应该能够使用自定义 AuthProvider 实现它并将当前设备的 Session ID 存储在 extended UserAuth table 中.基本上你想存储当前的 SessionId 和它的 DeviceUUID 如果它不同,删除旧的 Session.

您可以在身份验证期间在用于身份验证的 Authenticate.Meta 字典中发送其他元数据,或者如果愿意,可以在 QueryString 或 HTTP Headers 上添加其他信息,这些信息可以从 IRequest自定义 AuthProvider 中的上下文。

Sessions 只是简单的 AuthUserSession DTO 持续存在于 following format:

中注册的 ICacheClient
urn:iauthsession:{sessionId}

可以使用 IRequest.RemoveSession() 删除现有的 Session,例如:

req.RemoveSession(sessionId);

这将删除以前的 Session,他们将不再能够发出经过身份验证的请求。

如果您想通知现有设备它们已注销,您可以使用 Server Events to send a Custom Notification using the NotifySession() IServerEvents API 使用之前的 SessionId。或者,他们可以定期轮询 /auth(或发送一个空的 client.Get(new Authenticate()) 来检查他们是否仍然经过身份验证。

我解决问题的方法如下所示,尽管应该实施一种更有效的方法来检查同一 DeviceUUID 的重复会话。

  1. 我正在使用自己的自定义登录内容
  2. 当我成功登录后,我会检查所有 IAuthSessions 并检查具有相同 DeviceUUID 和 UserId(我的自定义 userId)
  3. 的其他会话
  4. 我使用 IAuthSession AuthProvider 来保存 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