2

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

因此,您可以在每台设备上启用一个会话,这意味着每个 Web 浏览器、每部手机、平板电脑等都有一个会话。例如,您不应被允许为同一部手机拥有两个或多个有效会话。

当我实现自己的会话缓存和身份验证结构时,我按照上面的方式实现了它,因为我的应用程序正在发送每个设备唯一的“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 中阅读过类似的帖子,但要么他们没有解决相同的问题,要么我不明白答案。

4

2 回答 2

2

没有明确支持此功能,但您应该能够使用自定义 AuthProvider 来实现它,并将当前设备的 Session Id 存储在扩展的 UserAuth表中。基本上你想存储当前的 SessionId 和它的 DeviceUUID,如果它不同,删除旧的 Session。

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

会话只是以以下格式AuthUserSession注册的普通 DTO :ICacheClient

urn:iauthsession:{sessionId}

可以使用删除现有会话的位置IRequest.RemoveSession(),例如:

req.RemoveSession(sessionId);

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

如果您想通知现有设备它们已被注销,您可以使用服务器事件通过NotifySession() IServerEvents API使用以前的 SessionId发送自定义通知。或者,他们可以定期轮询/auth(或发送一个空的 client.Get(new Authenticate()) 以检查他们是否仍然经过身份验证。

于 2018-02-12T21:15:52.420 回答
1

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

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

于 2018-02-13T21:59:07.010 回答