0

我正在使用 PostgreSQL 数据库运行 NodeJS express 应用程序。我正在使用节点缓存模块作为快速会话管理的存储。

该应用程序有一个用户管理方案,它由两种类型的用户组成,普通用户和管理员。管理员可以执行普通用户可以执行的所有任务。除此之外,管理员可以在应用程序中添加/删除用户,还可以向/从用户授予/撤销管理员权限。所以我的问题来了:

如果管理员在用户 X 仍然登录时从工具中删除了用户 X,那么在用户 X 发送到服务器的下一个请求时,他必须自动注销。类似地,如果管理员在用户 Y 仍然登录时撤销了用户 Y 的管理员权限,那么在下次点击服务器时用户 Y 应该会自动注销。

经过一番研究,我想出了两种实现方式:

1)授权每个请求- 即编写一个中间件来查询数据库并检查用户是否仍然具有工具访问权限。但是这种方法对于每个请求都有一个额外的数据库命中的开销。我认为这是一个很大的开销,因为在我的应用程序中,用户不会经常被删除,而且用户在已经登录时被删除的可能性也很小。

2)不要授权每个请求。相反,当删除用户的工具访问权限时,从缓存中删除该用户的会话(如果有)。因此,当该用户发送请求时,他将被注销,因为他的会话不再存在。但是,这样做并不是那么简单,因为节点缓存(甚至 Redis)没有任何“按值删除”功能。为此,我必须搜索缓存中的所有键,找到与需要删除会话的用户的 userID 值相同的键,然后删除这些会话。

我想知道哪种方法更好更有效,或者是否有第三种更好的方法。

4

1 回答 1

0

1)我不建议任何人采用第一种方法。当我扩大规模时,每个请求的数据库命中都会成为重大开销。此外,即使我没有执行任何数据库操作 (CRUD),而只是请求某些资源(例如网页),它也会让我查询数据库。

2)与第一种方法相比,我的第二种方法似乎要好一些。但是,按值搜索的复杂度为 O(n)。所以当我扩大规模时,这将需要更多时间。这种方法也引入了竞争条件。想象一个场景,我通过更新数据库来删除用户的访问权限,然后继续删除缓存中的用户会话。如果用户的数量很大,那么用户在访问被删除之后但在他的会话无效之前执行一些未经授权的操作的可能性很小。

对于这个问题,我想出了更多的解决方案:

3)存储用户ID作为键和会话ID作为值。但是,为此我必须确保我的用户 ID 是唯一的。这也有一个缺点,即在任何给定时间,用户只能激活一个会话。前任。如果用户已登录,但他再次从另一台机器/浏览器登录,那么他所有的旧会话都将失效。

4)通过将用户ID附加到会话ID来创建自定义会话ID。然后我可以通过指定模式来搜索键。此功能在 Redis 中可用,但不建议在生产代码中使用。此功能在我正在使用的节点缓存模块中不可用。尽管如此,它的复杂度仍然是 O(n)。

5) 使用 Redis 集来存储用户的所有会话 ID 与他的用户 ID。但是,我仍然必须存储会话 ID 与用户 ID 来维护会话的各个生命周期。删除用户访问权限后,我可以使用该集合检索所有用户会话 ID,并使用它们从缓存中删除所有会话。缺点是每次用户创建新会话/注销时,都应该更新集合和哈希。此外,应在会话到期时更新该集合。

6)在数据库中存储一个字段,指示用户是否已登录,以及一个包含他的活动会话列表的附加字段。这样我可以检查用户是否登录,如果是,则检索他的所有会话 ID,然后从缓存中删除它们。与方法 5 类似。

于 2020-07-04T13:00:58.883 回答