使用 Express Sessions、Redis 和 Passport 进行 Node.js 会话管理 - 第 1 部分 redis-session-demo 概述 如何运行 工作原理 分支

2025-06-07

使用 Express Sessions、Redis 和 Passport 进行 Node.js 会话管理 - 第 1 部分

redis-session-demo 概述

如何运行

它是如何工作的

分支

最近,我着手创建一个演示应用程序,用于我在纽约 Redis Day的演讲,该演示应用程序演示了会话管理如何在 Node.js/Express Web 应用中工作,使用 Redis 作为会话存储,并在其基础上添加身份验证功能。理解这些概念以及它们如何协同工作是一回事,但我之前从未真正构建过一个使用所有这些组件的应用程序。

作为初步研究的一部分,我查找了现有的教程或示例,它们可以实现我的目标。我找到了一些不错的博客 文章 教程,但没有一个能完全满足我的要求。本教程的第一部分将逐步指导您使用 Node.js 和 Express 构建一个 Web 应用,该应用使用express-sessionconnect-redis来帮助用户理解会话管理的工作原理。第二部分将在此基础上进行扩展,使用Passport实现身份验证,并探索身份验证和会话如何协同工作。

获取精酿啤酒名称演示应用程序的代码

我们将从一个简单的演示应用开始,一旦它启动并运行,我们将添加会话管理和身份验证。我们首先克隆包含演示应用代码的 GitHub 仓库,然后切换到 beer-demo 分支。

$ git clone https://github.com/jankleinert/redis-session-demo
$ cd redis-session-demo
$ git checkout beer-demo 
Enter fullscreen mode Exit fullscreen mode

让我们尝试运行该应用程序以确保其正常运行。

$ npm install
$ npm run dev
Enter fullscreen mode Exit fullscreen mode

在浏览器中打开http://localhost:3000,您应该会看到类似这样的内容。

演示应用程序截图

了解演示应用程序

该演示应用使用express-generator构建了应用框架。它使用Pug作为视图引擎。点击“Pour Another”按钮时,它会向API发出请求,该 API 将返回由机器学习生成的精酿啤酒名称。目前,该应用所做的就是这些。

我们将要使用的三个主要文件是app.js/routes/index.js/views/index.pug

目录结构

我们为什么要关心会话管理?

“会话”是一个含义丰富的术语,根据上下文可能含义迥异。在本教程中,我们讨论的是 Web 应用中的用户会话。您可以将其理解为 Web 应用内由单个用户发起的一系列请求和响应,从用户开始交互到会话结束或会话过期。

为什么我们关心或需要像会话这样的结构?HTTP 是无状态的,因此每个请求和响应对都是独立的。默认情况下,HTTP 不会维护任何状态,服务器也无法从一个请求到另一个请求知道您的身份。会话管理使我们能够为用户会话分配一个标识符,并使用该 ID 来存储与会话相关的状态或数据。这可以是用户是否经过身份验证、购物车中的商品等等——任何在会话期间需要保存的状态。

处理会话管理的方法有多种,但我们将研究一种特定的方法,即将会话数据保存在会话存储中,并且我们将使用 Redis 作为会话存储。

客户端和服务器

在客户端,Cookie 会存储会话 ID,但不存储任何会话数据。在应用程序的会话存储(本例中为 Redis)中,会话 ID 也会与会话数据一起存储。

向应用程序添加会话信息面板

为了方便直观地了解会话的运行情况,我们将在应用中添加一个会话信息面板。打开/views/index.pug并将以下代码添加到文件底部。注意缩进;.session应与 对齐在同一列h1

    .session
      p Session Info
      if sessionID
        p= 'Session ID: ' + sessionID 
      if sessionExpireTime
        p= 'Session expires in ' + Math.round(sessionExpireTime) + ' seconds'
      if beersViewed
        p= 'Beers viewed in this session: ' + beersViewed                           
Enter fullscreen mode Exit fullscreen mode

此面板将显示会话 ID、会话到期前剩余的秒数,以及我们的会话数据:本次会话中已浏览的啤酒名称数量。我们将在/routes/index.js后续步骤中指定这些值。

将 express-session 和 connect-redis 添加到 app.js

express-session是 Express 的会话中间件。它的设置和使用非常简单。市面上有很多兼容的会话存储可用于存储会话数据。我们将使用connect-redis。首先,安装所需的 npm 模块。

$ npm install --save express-session uuid redis connect-redis                       
Enter fullscreen mode Exit fullscreen mode

接下来,打开app.js并在现有的 s 下方添加以下代码requireuuid将用于生成用于我们的会话 ID 的唯一 ID。

const uuid = require('uuid/v4')
const session = require('express-session');
const redis = require('redis');
const redisStore = require('connect-redis')(session);   

const redisClient = redis.createClient();

redisClient.on('error', (err) => {
  console.log('Redis error: ', err);
});
Enter fullscreen mode Exit fullscreen mode

在继续下一步之前,请确保您已安装 Redis,并且 Redis 服务器正在运行。如果您需要安装 Redis,可以查看此文档。现在我们可以设置会话中间件,并告诉它使用我们的 Redis 存储作为会话存储。在 上方添加此代码app.use('/', indexRouter);

app.use(session({
  genid: (req) => {
    return uuid()
  },
  store: new redisStore({ host: 'localhost', port: 6379, client: redisClient }),
  name: '_redisDemo', 
  secret: process.env.SESSION_SECRET,
  resave: false,
  cookie: { secure: false, maxAge: 60000 }, // Set to secure:false and expire in 1 minute for demo purposes
  saveUninitialized: true
}));                            
Enter fullscreen mode Exit fullscreen mode

关于这段代码,有几点需要注意。存储会话 ID 的 Cookie 将被命名为“_redisDemo”。我们使用环境变量来设置密钥。下一步,我们将导出该环境变量(您可以随意设置)。为了更容易理解演示应用中的情况,我们将会话有效期设置为 1 分钟。在实际应用中,您应该将 maxAge 设置为更适合您应用的值。在终端中,停止运行nodemon,然后运行以下命令。

$ export SESSION_SECRET=some_secret_value_here && npm run dev                   
Enter fullscreen mode Exit fullscreen mode

将会话管理代码添加到/routes/index.js

最后一步是添加逻辑,用于跟踪每个会话中啤酒名称的浏览数量,并将会话相关信息传递到会话面板。打开/routes/index.js并将现有的代码替换getpost以下代码。

router.get('/', function(req, res, next) {
  var expireTime = req.session.cookie.maxAge / 1000; 
  res.render('index', { sessionID: req.sessionID, sessionExpireTime: expireTime, beersViewed: req.session.views, beerName: null, beerStyle: null, error: null });
});

router.post('/', function (req, res) {
  request('https://www.craftbeernamegenerator.com/api/api.php?type=trained', function (err, response, body) {
    if (req.session.views) {
      req.session.views++
    } else {
      req.session.views = 1
    }
    var expireTime = req.session.cookie.maxAge / 1000;   

    if(err){
      res.render('index', { sessionID: req.sessionID, sessionExpireTime: expireTime, beersViewed: req.session.views, beerName: null, beerStyle: null, error: 'Error, please try again'});
    } else {
      var beerInfo = JSON.parse(body)

      if(beerInfo.status != 200){
        res.render('index', { sessionID: req.sessionID, sessionExpireTime: expireTime, beersViewed: req.session.views, beerName: null, beerStyle: null, error: 'Error, please try again'});
      } else {
        res.render('index', { sessionID: req.sessionID, sessionExpireTime: expireTime, beersViewed: req.session.views, beerName: beerInfo.data.name, beerStyle: beerInfo.data.style, error: null});
      }
    }
  });
});                         
Enter fullscreen mode Exit fullscreen mode

我们做了哪些改动?在 中router.get,我们添加了expireTime,以便计算会话到期前的时间。然后在 中res.render,我们传递了一些额外的值:来自 的会话 ID req.sessionID、我们刚刚计算的到期时间,以及每个会话浏览的啤酒数量(存储为 )req.session.views。在会话的第一个页面浏览中,不会有 的值req.session.views,但我们的模板知道如何处理这种情况。

在 中router.post,我们发出啤酒名称的 API 请求后,如果这是会话中查看的第一个啤酒名称,我们会将其递增req.session.views或设置为1。然后,与上面看到的类似,我们会在 中传递与会话相关的其他信息res.render

会话管理正在进行中!

一切就绪后,在浏览器中打开http://localhost:3000。首次加载时,您应该会看到信息面板显示会话 ID 和会话到期时间。

点击“再来一杯”按钮(请在 60 秒内完成,以免会话过期),您应该会看到会话 ID 保持不变,并且会话中查看的啤酒数量也设置为1。如果您在浏览器中打开开发工具并查看 Cookie,您应该会看到一个名为 的 Cookie _redisDemo,其部分值将包含会话 ID。

带有 cookie 的会话

最后,如果您启动redis-cli然后发出以下命令,其中YOUR_SESSION_ID用浏览器中显示的会话 ID 替换,您应该会看到该会话存储在 Redis 中的会话数据,包括视图。

$ redis-cli
$ get "sess:YOUR_SESSION_ID"                            
Enter fullscreen mode Exit fullscreen mode

输出应该类似于以下内容:

redis-cli

继续试用一下这个应用,更好地理解会话的工作原理。如果你关闭浏览器,然后快速重新打开,会发生什么?如果你等待超过 60 秒后刷新页面,会发生什么?

至此,希望您对什么是会话管理以及如何使用express-session和为 Node.js 应用实现会话管理有了更好的理解connect-redis。在第 2 部分中,我们将在本教程的基础上,使用 Passport 为应用添加身份验证功能。

只想要第一部分的代码?点击此处获取:

GitHub 徽标 jankleinert / redis-session-demo

演示应用程序展示了使用 express-sessions 和 connect-redis 进行 Node.js 应用程序会话管理

redis-session-demo 概述

演示应用展示了如何使用 express-sessions 和 connect-redis 管理 Node.js 应用的会话。最初为 2019 年纽约 Redis Day 制作:https://events.redislabs.com/sessions/life-user-session/

该应用通过 API 查询机器学习生成的精酿啤酒名称,并将其显示在页面上。应用内置一个会话管理面板,用于显示会话 ID、会话到期时间以及该会话中浏览的啤酒名称数量。

在本教程中了解有关其工作原理的更多信息

如何运行

确保您已在本地运行 Redis 服务器:

redis-server

然后克隆这个 repo,运行 npm install,然后在开发模式下运行它:

git clone https://github.com/jankleinert/redis-session-demo
cd redis-session-demo
npm install
export SESSION_SECRET=<some value you choose>
npm run dev

然后在浏览器中访问http://localhost:3000。它看起来应该像这样:

截屏

它是如何工作的

本演示使用express-session进行会话管理,使用connect-redis作为会话存储。

分支

分支




文章来源:https://dev.to/jankleinert/node-js-session-management-using-express-sessions-redis-and-passport-part-1-cja
PREV
终于理解了响应式设计!
NEXT
很棒的命令行工具