Token-based 身份验证和 session/local 浏览器存储

Token-based authentication and session/local storage on browsers

好的,我想实现一个 Web 应用程序,该应用程序使用身份验证机制来个性化网站上的用户体验,但同时我有一些问题想解决。因此,一开始,用户将使用他们的用户名和密码登录(让我们暂时忘记第 3 方身份验证并假设有一个适当的注册页面)并且在成功登录后,服务器将生成一个令牌以用于后续调用该特定用户的浏览器。下面我想验证一下我的理解,并提出相关问题。

据我所知,在服务器端使用令牌要快得多(cpu-intensive,如果你愿意的话),因为现在不必解密存储在服务器上的密码并进行比较它与请求一起发送(例如使用 bcrypt),但检查要简单得多,归结为令牌是否已过期。作为一个额外的好处,用户名和密码等敏感信息不会重复传输。

检查点 1. 我们希望应用在用户有意或无意中按下 "Refresh/Reload" 时保持健壮,以便令牌在刷新后仍然可以使用(而不必使用凭据再次登录)。现在很清楚,要么我们必须使用 cookie(即 sessions),要么在客户端利用 session 存储或本地存储。还有别的办法吗?据我所知,答案是否定的(是的,本地存储有不同的选项,如 Web 存储、Web SQL 数据库、索引数据库和文件访问,但这超出了问题)。这是对还是错?此外,在客户端处理令牌(storage/recall)最常用的做法是什么?

检查点 2。 令牌到期。据我所知,这个想法是每次使用有效令牌时,都会更新该特定令牌的到期时间(比如 7 或 10 天后)。这有一个很好的好处,即定期访问该站点的用户只需登录一次。不利的一面似乎是暗示令牌对于同一用户保持不变 - 可能永远保持不变(当然除非令牌过期)。那么问题来了,这样安全吗?这里的另一个想法是在后端更新令牌,在客户端发送更新的令牌并在浏览器的本地存储上更新令牌,同时一切对最终用户都是透明的。这是一种常见的做法吗?我可以看到现在在服务器端需要对生成的令牌保持谨慎(参见下面的场景)。是否有处理此问题的通用做法(如果有人需要处理它)?

(假设用户A有两台设备A1和A2使用7天后过期的token TA1,用户B有设备B1使用7天后过期的token TB1。所有的token都存储在一些一种本地存储。六天后(即实际到期前一天),当用户 A 使用设备 A1 时,TA1 更新为 TA2。类似地,在那一天 TB1 更新为 TA1。现在,如果用户 A 使用设备 A2,这家伙有一个有效的令牌 (TA1),但在使用 API!)

时将以用户 B 的身份进行身份验证

检查点 3. 我一直认为 token-based 身份验证就是这样。通过 http 请求的 headers 发送的单个令牌,仅此而已。显然,如果还发送了用户名,那么我们就避免了发送密码,也避免了我上面描述的有问题的情况。但是,我不太喜欢这种方法。毕竟,现在令牌充当密码。唯一的节省是解密(即 cpu-cycles),同时在服务器端匹配凭据。这种做法是废话还是什么?

检查点 4. 如果将来有人想为智能手机或平板电脑创建专用应用程序,(据说)在 headers 的请求,而不是依赖于 cookie 和 sessions(参见 cookie 容器)。目前这对我来说是次要的,但这是真的吗?

我认为上述问题与实现无关,但如果您想为开发提供指导,我将使用 node.js。

1:Cookie 是存储令牌的首选方法client-side。

2:您可以 re-auth 用户并发回更新的令牌,或者只是延迟令牌的到期时间。这在很大程度上取决于您如何存储令牌,以及如何处理过期机制(例如 Mongo 的生存时间机制,或 SQL 数据库中的 'expiresAt' 字段等).您概述的用户劫持另一个用户的场景 session 应该不可能通过正确的令牌生成。

3:令牌应该是授权用户所需的唯一令牌。在服务器端,一旦您获得了令牌,您只需执行一个操作来检索用户 object。这在很大程度上取决于您如何设置系统。例如,您可以将其设置为将签名令牌直接解码为用户 object,或者如果您使用持久性存储来存储令牌,请使用令牌作为查询中的键。

4:发送令牌时,无论平台如何,最好使用请求的headers。 Cookie、本地存储等仅仅是将令牌保存在用户设备上的工具。

如果您的应用使用 Node.js,我建议您查看 angular-fullstack 中的身份验证处理方式,它使用 Passport 和与您类似的外部承载策略正在尝试做。