【问题标题】:PassportJS - Is it possible to change req.user for another user?PassportJS - 是否可以为另一个用户更改 req.user?
【发布时间】:2017-01-04 17:41:01
【问题描述】:

在我的应用程序中,我已经实现了更改用户权限、排名等的功能。效果很好,如果我更新自己的权限,我可以立即看到更改,因为我可以通过 @ 更新 req.user 对象987654321@。问题是,当我更新另一个用户的权限时,它在数据库中更新得很好,但是用户必须重新登录才能看到他们的权限更改,因为req.user 仍然认为他们没有权限。如果他们当然没有登录,这很好,但如果他们登录了,我希望尽可能立即为他们反映更改。

所以我想知道是否有办法更新其他用户 req.user 对象,以便他们可以立即看到他们的权限更改而无需注销并重新登录?

或者可能是一种在返回之前注销并登录该用户的方法?

【问题讨论】:

    标签: node.js express passport.js


    【解决方案1】:

    由于权限在您自己的数据库中,所以您当然可以,但如何操作取决于您的应用。

    假设您正在使用会话,存储在req.user 中的对象将使用您为passport.deserializeUser 提供的函数为每个HTTP 请求单独加载。通常您会将用户 ID 存储到会话中passport.serializeUser,然后从数据库中检索用户 ID 为deserializeUser。因此,无论何时在后端处理请求时,您通常都会在req.user 中获得最新信息,包括权限。自然,您的前端还需要以某种方式获取新权限并进行自我调整(例如,如果您向用户添加管理员权限,您可能希望他们在 UI 中看到管理员选项)。

    您当然可以将整个用户对象传递给会话存储并跳过每个请求一次数据库调用,即。使用这些:

    passport.serializeUser(function(user, cb) { cb(null, user); });
    passport.deserializeUser(function(user, cb) { cb(null, user); });
    

    用于会话处理。如果您这样做,那么数据库更改不会反映在 req.user 对象上。如果用户更新了自己的信息,您可以拨打req.logIn(...),但您不能拨打其他用户的电话。你可以解决这个问题 - 例如。通过 websocket 通知有问题的用户,并让他们的浏览器调用一个使用最新用户对象调用 req.logIn 的路由,或者深入会话存储并直接在那里操作数据。

    或者,由于强制注销是一个选项,您可以按照 enRaisers 的回答并从会话存储中找到用户会话并将它们全部删除,这实际上是从后端注销用户。您可以通过 API 浏览会话,或者如果您使用数据库(例如 connect-mongoconnect-redis)进行会话存储,您还可以打开另一个到同一数据库的连接并使用正常的搜索和销毁方法。同样,您仍然需要以某种方式自行处理前端的注销。

    【讨论】:

    • 感谢您的回复。所以我更改了我的反序列化函数以从数据库中获取用户,现在req.user 将在用户刷新页面后更新。我想得越多,我认为问题的根源在于我正在验证基于req.user 的权限,以避免每次有人基于权限执行某些操作时运行数据库查找(这种情况经常发生)。作为比我更有经验的人,您认为使用 db 查找验证用户权限而不是始终保持req.user 更新是否可以?这并不是一个庞大的应用程序。
    • 一般来说,我会说跳过通过其 ID 获取一个项目的查询是微优化,在我的项目中访问deserializeUser 中的数据库从来都不是问题。 I query-by-unique-id 可能是几乎每个数据库中最快的查询方法,通常如果您一次又一次地询问同一行,数据库会做一些事情来加快速度。仅供参考,我从我的 14M 行 Postgres 数据库中按 ID 查询了一行,第一个查询是 65ms。相同 ID 的第二次查询是 0.063 毫秒。
    • 是的。谢谢你的建议!我最终通过将我的护照反序列化方法更改为:passport.serializeUser(function(user, done) { done(null, user.id); }); passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { done(err, user); }); }); 来解决这个问题,它使req.user 保持最新。在前端(在我的例子中是 Angular 1)我还通过调用返回 req.user 的路由来更新用户的每次路由更改,以保持视图更新。希望这对其他人有帮助:)
    【解决方案2】:

    您可以尝试删除会话,或者重新生成会话ID。但这将迫使该用户重新登录。

    如果您的会话存储在 mongodb 中。然后您可以按名称 app_sessions 检查集合,它有一个名称为 userId 的字段。

    在 Express 会话中有一个名为 store 的模块。它提供了许多 API 来通过 sessionID 查找会话。但不幸的是,没有 API 可以通过用户 ID 查找会话。

    因此,如果您想使用session store API,则可以调用 store.all ,这将提供所有会话。但这确实是一种残忍的方法。因为我不知道它可能持有多少数据。

    【讨论】:

    • 我确实使用 Mongodb,但其中没有包含 app_sessions 的集合。同样据我所知,注销用户似乎会删除我认为可以的会话,但我该如何对另一个用户执行此操作?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-03-22
    • 1970-01-01
    • 2021-03-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多