我们将应用程序构建为一系列组件,使用 Redis 作为数据存储和缓存。这些组件中的大多数通过 HTTP 请求/响应周期与用户进行通信,HTTP 请求/响应周期本质上是无状态的。但是,我们希望在某些情况下维护状态,或者记住用户从一个请求到下一个请求的信息。
我们可以通过让应用程序在返回给用户的响应中设置 cookie 来识别用户 - 然后他们的浏览器将把这个 cookie 附加到未来的请求中。这可以用于在服务器端会话对象中存储有关用户的信息,Express 通过 cookie 中的 ID 来跟踪会话对象。
可以将 cookie 视为一种键,并将会话对象视为一个值。我们可以将它们存储在服务器的内存中,但这会将我们限制在一个服务器实例中,如果该实例崩溃并重新启动,就会丢失所有会话数据。
幸运的是,Redis 是会话数据的绝佳存储位置 - 它速度快且持久,并允许我们通过添加更多实例来横向扩展系统组件。我们使用了 npm 包“connect-redis”将 Redis 添加为身份验证和签到接收器服务的会话存储,只需要很少的代码。
在本练习中,您将启用签到接收器服务中的身份验证功能,并使用 Postman 与身份验证服务建立会话以向系统提交经过身份验证的签到。
首先,如果签到接收器正在运行,请停止它。在它的终端窗口中按 Ctrl-C。
现在,使用启用的可选身份验证功能重新启动签到接收器
$ npm run checkinreceiver auth
> js-crash-course@0.0.1 checkinreceiver
> node ./src/checkinreceiver.js "auth"
info: Authentication enabled, checkins require a valid user session.
info: Checkin receiver listening on port 8082.
请注意,签到接收器报告现在已启用身份验证。
在第二个终端窗口中,cd 到您克隆项目存储库所在的 node-js-crash-course 目录,并启动身份验证服务,该服务将在端口 8083 上监听
$ npm run auth
> js-crash-course@0.0.1 auth /Users/simonprickett/source/github/node-js-crash-course
> node ./src/auth.js
info: Authentication service listening on port 8083.
在 Postman 中打开一个新的请求,并发出一个 POST 请求以执行以下签到
单击“发送” - 这次,签到接收器服务应该拒绝请求,因为您尚未通过系统进行身份验证。您应该看到 401 未授权响应
在签到接收器的终端窗口中,您应该看到它拒绝了您的请求,因为它找不到您的会话
debug: Rejecting checkin - no valid user session found.
签到接收器拒绝了您的请求,因为它在您的请求会话中找不到“user”的值(查看 src/checkinreceiver.js
中的代码)。
让我们再试一次,但这次我们先登录。这将建立一个会话,我们将能够看到它如何在 Redis 中存储……
保留您在 Postman 中的签到请求选项卡,并打开一个新选项卡以创建一个 POST 请求到身份验证服务。
将 URL 设置为 localhost:8083/login
,并将 JSON 主体设置为
{ "email": "al.appelhof@example.com", "password": "secret123" }
您的请求应该如下所示
单击“发送”以登录。身份验证服务将检查提供的凭据是否与 Redis 中键 ncc:user:77
处存储的凭据一致,并为该用户创建一个会话对象,将电子邮件地址添加到会话中的“user”属性。Postman 应该显示 200(成功)响应代码和文本“OK”。
单击 Postman 中的蓝色“Cookies”文本,您应该看到在 localhost 上为“checkinapp”设置了一个 cookie。单击“checkinapp”文本查看 cookie 的内容
现在切换回 Postman 中具有用户 77 签到请求的选项卡。再次发送请求,这次应该会成功,因为 Postman 也会发送包含会话 ID 的 cookie,然后签到接收器将能够验证您是否具有经过身份验证的会话。这次,您应该获得 202 已接受响应
当签到接收器收到您的请求时,它使用 cookie 中的值来查找和加载您在 Redis 中的会话(connect-redis 为我们做到了这一点),然后检查会话是否设置了“user”属性。在 localhost URL 上运行的任何系统组件现在都可以访问您的会话并查询和存储信息。
最后,让我们看看会话在 Redis 中的样子…… 使用 redis-cli 或 RedisInsight 浏览器,按以下方式查找所有会话键
127.0.0.1:6379> keys ncc:session:*
1) "ncc:session:Blvc-93k2TckafgwS0IDAHfW-MPGhqyl"
请注意,键名包含 cookie 中的会话 ID。connect-redis 为我们管理这些键作为 Redis 字符串,我们应用程序需要做的就是操作请求的会话对象。
让我们看看我们会话中的内容以及它的过期时间
127.0.0.1:6379> get ncc:session:Blvc-93k2TckafgwS0IDAHfW-MPGhqyl
"{\"cookie\":{\"originalMaxAge\":null,\"expires\":null,\"httpOnly\":true,\"path\":\"/\"},\"user\":\"al.appelhof@example.com\"}"
127.0.0.1:6379> ttl ncc:session:Blvc-93k2TckafgwS0IDAHfW-MPGhqyl
(integer) 85693
我们在设置 connect-redis 时没有在代码中指定会话长度,因此默认情况下它在一天后过期会话。
最后,让我们从身份验证服务中注销,并确保我们的会话数据从 Redis 中删除。在 Postman 中,创建如下 GET 请求,然后单击发送
注销处理程序中的代码会破坏您的会话,然后您的会话应该从 Redis 中消失
127.0.0.1:6379> get ncc:session:Blvc-93k2TckafgwS0IDAHfW-MPGhqyl
(nil)
接下来,我们将继续讨论如何扩展我们的签到处理以应对所有这些新用户!