授权每个请求vs从缓存中删除用户会话

问题描述 投票:0回答:1

我正在使用PostgreSQL DB运行NodeJS Express应用程序。我正在使用节点缓存模块作为Express中会话管理的存储。

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

如果管理员X仍然在用户X上登录时,管理员从工具中删除用户X,则在用户X发送到服务器的下一个请求上,他必须自动注销。同样,如果管理员在仍登录的情况下撤消了用户Y的管理员权限,则在下次访问服务器时,用户Y应自动注销。

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

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

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

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

node.js express session express-session role-based-access-control
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)将一个字段(指示用户是否已登录)存储在DB中,并将另一个字段(包括其活动会话的列表)存储。这样,您可以检查用户是否已登录,如果是,则检索其所有会话ID,然后从缓存中将其删除。类似于方法5。

© www.soinside.com 2019 - 2024. All rights reserved.