Next-auth (JWT) 日志记录会话

Next-auth (JWT) logging sessions

根据 Next-auth 文档,因为我们使用凭据提供程序连接到我们的用户集合以获取用户名和密码,Next-Auth 不使用会话数据库来检查会话是否处于活动状态。

If you use a custom credentials provider user accounts will not be persisted in a database by NextAuth.js (even if one is configured). The option to use JSON Web Tokens for session tokens (which allow sign in without using a session database) must be enabled to use a custom credentials provider.

我想添加一个 _middleware,它允许我存储并检查会话数据库中的最新 JWT 会话是否与用户当前使用的最新会话相匹配。

原因是,如果我在技术上有两台设备,我将能够在两台设备上登录,目前它们还没有真正的方法来辨别来自 PC2 的用户是否也在 PC1 上登录。

所以我的理论是添加以下内容,但不确定这是否可行。

callbacks: {
        jwt: async ({ token, user }) => {
          console.log("running JWT - because of custom login")
            user && (token.user = user)
            
            (ADD CODE HERE TO SAVE TOKEN & CHECK IF TOKEN IS LATEST TOKEN + VALID - INSIDE SESSION DATABASE)

            (IF OLD-TOKEN IS NO LONGER VALID OR THE LATEST TOKEN LOG THE USER OUT)

            console.log("TOKEN IS "+ JSON.stringify(token))
            return token
        },
        session: async ({ session, token, user }) => {
            console.log(JSON.stringify(session) +" / "+ JSON.stringify(token) +"/"+ JSON.stringify(user));

            
            session.user.tokenID = token //ADD CODE HERE TO SAVE TOKEN TO SESSION COOKIE

            session.user = user
            return session
        }
      },

然后,如果我创建一个中间件来检查此 tokenID 并将其与会话数据库匹配,以及它是否是来自所述用户的最新结果。

例如

说PC1(user1)在这里登录

{
_id: 1
tokenID: 918171-918171-81716-0887
userid: 00-00-00-001
expire: "2022-05-23T12:47:04.593Z"
}

但随后 PC2 也 (user1) 再次登录并创建了一个新会话

{
_id: 2
tokenID: 71888-651777-616666-0117
userid: 00-00-00-001
expire: "2022-05-24T12:47:04.593Z"
}

我需要中间件做的(一个简单的 mongodb 查询就可以做到)是检查它们是否是为相同用户 ID 存储的旧会话,如果是,则从 PC1 注销。

现在我发现这个想法有一些问题。

  1. 其他提供者会话(使用会话数据库)使其更难验证
  2. 每次您调用注册页面或会话时,它似乎都会重新 运行 JWT 部分 - 理论上这很好,因为我们可以使用 findOne 更新函数,如果令牌在会话中,那么只需更新过期时间——但是这会导致 PC2 登录后 PC1 刷新,然后 PC1 过期时间可能比 PC2 过期时间长(但是一个简单的排序功能将允许我们查看 ID 是否比 PC2 更旧,如果是这样注销的话)。
  3. 每次重新加载页面时 JWT 都会更改令牌

这对隐私和用户数据有何帮助?

我知道 Next-Auth 可能不想这样做,这就是为什么我问这个问题,什么是实现我想要实现的目标的最佳实践。

此答案基于以下确认:问题是您希望用户一次只能登录一个 computer/device,并且您正在使用用户名和密码进行身份验证他们。

在那种情况下,您还需要有一个数据库,用于在每个发布的 JWT 中记录一个令牌。没有数据库是不可能解决这个问题的。

以下是使用 JWT 和数据库解决问题的方法:

  • 在每次新登录时,您需要使用 jwt 回调向每个 JWT 添加类似 UUID 的内容,然后在数据库中记录该 UUID 、用户 ID 和 JWT 过期时间.
  • 在那个回调中,如果数据库中有相同用户 ID 的其他条目,您应该将它们标记为无效(或从数据库中删除它们)。
  • 每次在同一个回调中读取现有的 JWT 时,您需要检查数据库中的 UUID 是否仍然有效(即仍然存在/不指向与标记为的 JWT 相对应的 UUID已过期),如果它不再有效,请不要 return 一个有效的 JWT。
  • 您可能还想在 session 回调中添加特殊处理,通过在他们退出的计算机的用户界面中优雅地处理它来做类似的事情来改善用户体验。

实际上,这具有 JWT 的所有缺点以及会话数据库的所有缺点(尽管在某些特殊情况下这是一种更可取的方法)。

我不建议使用用户名和密码或限制用户一次只能登录一台计算机,但是考虑到那些异常具体的限制(这也需要一个对性能有负面影响的解决方案)您可能需要考虑一个不同的身份验证解决方案 and/or 想一想您还可以如何解决这个试图解决的潜在需求(以及是否值得成本和复杂性)。