【问题标题】:Logging user out on time expiry按时注销用户
【发布时间】:2021-10-28 23:38:46
【问题描述】:

我正在开发一个 nodejs(express) 服务器和一个使用 API 的 react FE。服务器令牌存储令牌和秘密。当用户退出 FE 时,secret 会被刷新。 (原始开发人员使用自定义身份验证而不是 JWT ..) 问题是,如果用户不按注销按钮,他们可以无限期地登录。就解决方案而言,我有一个想法,服务器可以以某种方式监视来自客户端的最后一个请求,当 30 分钟过去后,服务器可以更新秘密——我手动尝试了这个,当客户端刷新时,api 调用失败不优雅。我可以在 FE 中构建一些额外的逻辑,捕获向用户显示注销消息的错误,然后删除本地存储。 此外,客户端可以从最后一次调用 api 算起 25 分钟,并在退出用户之前显示带有倒计时的对话框。

也许,我把这个复杂化了,还有另一种方法 - 目前使用本地存储,但不确定我是否要使用 cookie,它可以解决浏览器不活动或浏览器关闭时自动注销的问题,以及是否有可能在 cookie 过期之前有一个对话倒计时(如果用户选择保持会话打开,则会更新)

如果有可行的选择,将不胜感激。

代码:

api/createCustomer

schemaObj.customerToken = crypto.createHash('sha1').update(uuidv4()).update(config.hidden.salt).digest('hex');
schemaObj.customerSecret = crypto.createHash('sha256').update(uuidv4()).update(config.hidden.secret).digest('hex');
schemaObj.password = bcrypt.hashSync(password, bcrypt.genSaltSync(10));


api/login

var loginValid = bcrypt.compareSync(password, bidder.password);
....
res.apiSuccess(customer);

反应代码:

axios.post('/api/login', formData)
let { customerToken, customerSecret, isVerified } = res.data.data;
.....

localStorage.setItem("customerData", JSON.stringify({ customerToken, customerSecret }));

【问题讨论】:

  • JWT 或任何其他密钥,由于 XSS 攻击,不应存储在本地存储中。您能否详细说明此自定义令牌系统的工作原理?它是会话还是熊令牌或像 jwt 之类的 json(具有 expire 属性)
  • 不知道如何回答您的问题,您能从我添加到帖子中的服务器代码看出吗? -
  • 是的,有点帮助。 customerToken 和 customerSecret 有什么区别?
  • customerToken 是客户 ID,customerSecret 充当密码。这两个都被发送到 FE。当从 FE 调用 api 时,这两个 customerToken customerSecret 都会传回服务器并进行身份验证。当客户手动注销时,customerSecret被刷新,
  • 当react收到secret时,将其存储在本地存储中。秘密被发送回服务器以进行所有安全 api 调用。服务器检查传入的秘密并将其与存储的版本进行比较,如果发生匹配,则允许处理。没有过期检查。当令牌首先在服务器上生成时,任何地方都不会记录到期。

标签: node.js express authentication cookies


【解决方案1】:

如果你想在登录时过期,你必须在某处保存一个时间戳属性来检查它。大多数标准身份验证系统都有此功能,例如JWT 有 exp 声明,cookie 有 max-age。

对于像您描述的那样的自定义系统,您需要自己跟踪。

据我了解系统

  • customerToken = 客户 ID
  • customerPassword = 登录密码
  • customerSecret = 与所有从响应到服务器的请求一起发送的实际令牌。

所以服务器接收到 customerSecret,它有一个中间人会根据数据库检查该秘密,以检查是否应该允许用户继续。

你的选择很少

将列 logintime 添加到您的用户表中。

  • 当用户登录时,使用当前时间戳更新该字段。
  • 在数据库中查找密钥时,检查登录的时间戳是否在 30 分钟内。

使用 cookie

  • 当用户登录时,将密钥添加到 cookie。
  • 在 react 应用程序中使用 withCredentials 将 cookie 发送到服务器
  • 在中间检查cookie而不是查看数据库

将秘钥移到redis中

  • 当用户登录时,使用 expire 属性将 secret 添加到 redis。
  • 从 react 作为 Bearer 发送秘密
  • 在 middelewere 中查找 redis 中的 secret 以检查用户。

在身份验证和授权方面总体来说很少有指针:

  • 针对每个请求读取完整的事务数据库的成本很高。
  • 会话状态具有数据丢失容错性,即使丢失也没关系,您可以随时重新创建/恢复它。
  • 您永远不应将机密或令牌存储在 localStorage 中,因为它位于客户端上,因此可供其他应用程序访问。

【讨论】:

  • 谢谢。选择“使用 Cookie”或“将秘密移至 redis”选项 - 这是否意味着我不再需要在数据库中存储秘密?在这两个选项中,秘密和到期都被发送到 FE,当 cookie 即将到期时,我是否可以在 FE 上启动一个脚本来提示用户更新 cookie(刷新 cookie 可以重新启动客户端计时器)?
  • 是的,您不需要将秘密存储在数据库中。是的,当有来自 FE 的请求时,您可以检查 cookie 和/或 redis 的过期时间,如果它可能是 5 分钟或更短,您可以再次将其更新为 30 分钟。
  • 嗨,如果我使用 cookie,当返回到服务器时,我可以返回 customerToken 和 customerSecret - 然后服务器需要根据 Redis 或 DB 检查这两个。如果找到,则检查存储的到期时间。如果到期即将结束,则续订。我想我不需要 customerToken 来回走动(因为它总是一样的),但是 customerSecret 需要去 FE 和 BE,因为它会经常刷新。这有意义吗?
【解决方案2】:

可能是这样的

setTimeout(function(){ req.session.destroy(); }, milliseconds_since_page_loaded);

或使用 req.session.destroy();最适合的地方。我不确定我是否完全理解您何时想要超时。

也许您可以将变量设置为自上次调用以来的时间,然后每分钟给它 ++,然后添加到执行调用以重置它的任何函数,并且每 30 分钟/不管多长时间检查一次该变量.

【讨论】:

  • 理想情况下,我想在用户停止与前端交互后 30 分钟超时。你提到的代码是服务器端的吗?
  • 是服务器端。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-11-23
  • 1970-01-01
  • 1970-01-01
  • 2018-03-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多