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