前端进阶之旅前端进阶之旅
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket

# express+session实现简易身份认证

30 秒速记

  • 套路:登录校验密码 → 服务端存 session → 浏览器只拿一个 session id 的 cookie → 后续请求凭它查人
  • 登录成功先 req.session.regenerate() 换新 id,防会话固定
  • 退出 = req.session.destroy() 删服务端记录 + res.clearCookie() 清浏览器
  • 默认的 MemoryStore 只能本地玩:重启就丢、会泄漏内存、多实例不共享,生产换 Redis 这类共享存储
  • cookie 配 httpOnly(默认就开)、secure、sameSite,写操作还要防 CSRF

express-session 做登录,本质是「数据放服务端,浏览器只拿一张号码牌」。 用户登录成功后,服务端把用户名写进 req.session,中间件负责生成一个随机的 session id、签名后通过 Set-Cookie 发给浏览器;之后每个请求带着这张号码牌来,服务端凭它找回会话数据,判断你是谁。我做这类功能会盯三件事:登录后要 regenerate 换号,退出要在服务端真删,生产环境的 store 必须是多实例共享的。

理解「express+session实现简易身份认证」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1登录成功后前端存个 isLogin = true,刷新就没了,这算身份认证吗?
参考回答

不算,那只是页面里的一个变量,后端根本不知道。认证状态得在服务端,每个受保护的接口都要从 req.session 里查一遍,前端那个变量顶多用来决定显示哪个按钮。

追问 2从一台机器扩到两台,用户登录后翻一页就变回未登录,为什么?
参考回答

会话存在第一台的内存或本地文件里,第二个请求被负载均衡打到另一台,那里查不到这个 session id。正解是换共享 store,比如 connect-redis;nginx 的 ip_hash 粘性会话能临时止血,但一台挂了那批用户还是全掉线。

追问 3登录接口返回成功,一跳转又回到登录页,你先看什么?
参考回答

先看网络面板:登录响应里有没有 Set-Cookie,下一个请求有没有把它带上。没带的话常见原因是 secure: true 但走的是 HTTP,或者跨域请求没开 credentials。带了还不行,再看服务端 store 里有没有这条记录。

追问 4登录成功为什么要调 regenerate,直接往 req.session 里写用户名不行吗?
参考回答

不换 id 会有会话固定攻击:攻击者先拿一个自己的 session id 塞给受害者,受害者用它登录后,攻击者手里那个 id 也就变成已登录了。regenerate 会作废旧 id、发一个新的,这一步很便宜,没理由省。

# 环境初始化

30 秒速记

  • express -e:用 express-generator 生成骨架,-e 表示模板用 EJS
  • npm install 装骨架自带的依赖,脚手架本身不帮你装
  • npm install express-session session-file-store:会话中间件 + 把会话存成本地文件的 store
  • npm 5 以后 --save 是默认行为,加不加都会写进 package.json
  • session-file-store 只适合单机演示,多实例生产换 connect-redis 之类的共享存储

环境初始化就三步:脚手架生成项目、装基础依赖、再装会话相关的两个包。 express -e 生成一个用 EJS 模板的 Express 骨架,这一步只建文件,不装依赖,所以紧接着要 npm install。然后装 express-session 负责会话逻辑,session-file-store 负责把会话数据写到项目下的 sessions 目录,方便你打开文件直接看里面存了什么。拿来学原理很直观,但上线别用文件存储,多台机器之间是不共享的。

首先,初始化项目

express -e
@前端进阶之旅: 代码已经复制到剪贴板

然后,安装依赖。

npm install
@前端进阶之旅: 代码已经复制到剪贴板

接着,安装session相关的包。

npm install --save express-session session-file-store
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1执行 express -e 提示命令不存在,怎么办?
参考回答

express 命令来自 express-generator,要先 npm i -g express-generator。现在更推荐不全局装,直接 npx express-generator -e,版本也不会跟别人机器上的对不上。

追问 2本地能跑,同事拉代码后启动报 Cannot find module 'express-session',问题在哪?
参考回答

八成是你装的时候没写进 package.json,只躺在自己的 node_modules 里。看一下 dependencies 有没有这一项,再确认 package-lock.json 一起提交了。在干净目录 npm ci 跑一遍,是最快的验证办法。

追问 3session-file-store 存的会话文件会越堆越多吗?
参考回答

它有个 reapInterval 参数,默认每小时清一次过期文件,所以不会无限增长。但这只是本机文件,进程多开几个、机器多加几台就各管各的,这也是它只适合演示 的原因。

追问 4这个演示项目要改成生产服务,依赖要换哪一个?
参考回答

把 session-file-store 换成 connect-redis 加一个 Redis 客户端,express-session 本身不用换。所有实例连同一个 Redis,会话自然共享,过期也交给 Redis 的 TTL 处理。

# session相关配置

30 秒速记

  • name:cookie 名,默认 connect.sid,改个名可以少暴露技术栈
  • secret:给 session id 签名的密钥,可以传数组做轮换,别硬编码在代码里
  • store:会话数据放哪,示例是本地文件,生产用 Redis
  • saveUninitialized: false:没往 session 写过东西就不落库、不发 cookie,匿名访客不产生垃圾会话
  • resave: false:会话没改就不回写,避免并发请求互相覆盖;store 支持 touch 时设 false 就行
  • cookie.maxAge 单位是毫秒,示例 10 * 1000 就是 10 秒,方便看过期效果

这段配置决定了四件事:cookie 叫什么、拿什么签名、数据存哪、多久过期。 最容易被问的是 saveUninitialized 和 resave。saveUninitialized: false 的意思是用户没登录、你也没往 req.session 写过东西,就不创建会话,否则每个路过的访客都会生成一个会话文件;resave: false 是会话内容没变就不重新写回存储,两个并发请求都回写的话,后完成的那个可能把前一个的修改覆盖掉。示例里 maxAge 只有 10 秒,是故意为了演示过期,真实项目一般是小时或天级别。

配置如下,并不复杂,可以见代码注释,或者参考 官方文档。

var express = require('express');
var app = express();
var session = require('express-session');
var FileStore = require('session-file-store')(session);

var identityKey = 'skey';

app.use(session({
    name: identityKey,
    secret: 'chyingp',  // 用来对session id相关的cookie进行签名
    store: new FileStore(),  // 本地存储session(文本文件,也可以选择其他store,比如redis的)
    saveUninitialized: false,  // 是否自动保存未初始化的会话,建议false
    resave: false,  // 是否每次都重新保存会话,建议false
    cookie: {
        maxAge: 10 * 1000  // 有效期,单位是毫秒
    }
}));
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1公开首页没登录,每次访问都会多出一个会话文件,最可能是哪项配置的问题?
参考回答

saveUninitialized 被设成了 true,未初始化的会话也会被保存并下发 cookie。改回 false;如果还在产生,看看是不是有别的中间件往 req.session 里写了东西,比如记录访问来源。

追问 2用户反馈每隔 10 秒就要重新登录,服务端也没报错,怎么回事?
参考回答

cookie.maxAge 还是示例里的 10 * 1000,浏览器 10 秒后就把 cookie 扔了。改成业务需要的时长,同时让 store 的过期时间对齐;想要「有操作就续期」再加 rolling: true。

基础篇
进阶篇
高频篇
精选篇
手写篇
面经篇
AI 篇
原理篇
每日一题
小程序题库
知识卡片
  • 场景篇按分类整理的大前端场景考点
  • 历年面经按年份追踪真实考点
  • 算法题库NEW在线编码即时判题
  • 专项自测100 题快速查漏
  • 前端基础
    • HTTP从报文一路讲到 HTTPS
    • 浏览器渲染、事件循环、进程
    • 计算机基础Linux、网络、操作系统
  • 进阶专项
    • 设计模式23 种模式怎么用
    • 前端系统进阶学习大型项目工程化
    • 前端综合文章长期沉淀的实践文
  • 工程与工具
    • Node学习指南从环境搭建到服务端
    • NPM工作流script、依赖与发布
    • Docker容器化部署上手
    • Canvas图形与动画实战
  • 路线与导图
    • 思维导图知识点全景图
    • 学习路线按图索骥不跑偏
  • 动态
    • 公众号动态公众号历史文章
    • 博客动态站长的技术博客
    • 开发者导航常用工具与文档站
  • AI 助手随时提问,即时解析
  • AI 模拟面试模拟真实面试 + 报告
  • AI 知识地图串起全站知识点
  • AI 定制路线按你的简历现排
AI 热点
旧版
  • 基础篇

    • 环境搭建
    • node部署
    • 基础应用
  • 内置模块

    • 1.0 本地路径处理 path
    • 2.0 文件系统操作 fs
    • 3.1 基础调试 console
    • 3.2 本地调试远程服务器上的Node代码
    • 4.1 网络服务 http
    • 4.2 网络服务 http res
    • 4.3 网络服务 http req
    • 4.4 网络服务 http server
    • 4.5 网络服务 http client
    • 4.6 网络服务 https
    • 4.7 网络TCP net
    • 4.8 网络UDP dgram
    • 4.9 域名解析 dns
    • 5.0 网络地址解析 url
    • 5.1 URL查询字符串 querystring
    • 6.1 流操作 stream
    • 6.2 逐行读取 readline
    • 7.1 进程相关 process
    • 7.2 子进程 child
    • 8.1 二进制数据 buffer
    • 8.2 二进制解码 string_decoder
    • 9.1 事件机制 events
    • 9.2 实用工具模块 util
    • 9.3 数据加密 crypto
    • 9.4 MD5入门介绍及crypto模块的应用
    • 9.4 资源压缩 zlib
    • 9.5 集群 cluster
    • 9.6 v8
  • 进阶篇

    • 5分钟入门非对称加密用法
    • cluster
    • cookie_parser深入
    • crypto模块之理论篇
    • express+cookie_parser签名机制深入剖析
    • express+session实现简易身份认证
      • 环境初始化
      • session相关配置
      • 实现登录/登出接口
        • 创建测试账户数据
        • 登录、登出接口实现
        • 登录态判断
        • UI界面
      • 相关链接
    • https
    • log4js入门实例
    • node8_napi
    • 使用 async 控制并发
    • 使用 eventproxy 控制并发
    • 使用 superagent 与 cheerio 完成简单爬虫
    • 基于express+muter的文件上传
    • 将图片转成datauri嵌入到html
    • 常用中间件 body_parser 实现解析
    • 日志模块morgan
    • 服务端字符编解码&乱码处理 charset_enc_dec
    • 测试用例mocha,should,istanbul
    • 调试日志打印debug模块
  • Express

    • 1.1 Express概览篇
    • 1.2 Express
  • Koa2

    • 1.0 koa2概览篇
    • 1.1 快速开始
    • 1.2 async await使用
    • 1.3 koa2简析结构
    • 1.4 koa中间件开发与使用
    • 10.1 单元测试
    • 11.1 开发debug
    • 12.1 快速启动
    • 12.2 框架设计
    • 12.3 分层操作
    • 12.4 数据库设计
    • 12.5 路由设计
    • 12.6 webpack4环境搭建
    • 12.7 使用react
    • 12.8 登录注册功能实现
    • 12.9 session登录态判断处理
    • 13.1 import export使用
    • 2.1 原生koa2实现路由
    • 2.2 koa router中间
    • 3.1 GET请求数据获取
    • 3.2 POST请求数据获取
    • 3.3 koa bodyparser中间件
    • 4.1 原生koa2实现静态资源服务器
    • 4.2 koa static中间件
    • 5.1 koa2使用cookie
    • 5.2 koa2实现session
    • 6.1 koa2加载模板引擎
    • 6.2 ejs模板引擎
    • 7.1 busboy模块
    • 7.2 上传文件简单实现
    • 7.3 异步上传图片实现
    • 8.1 mysql模块
    • 8.2 async await封装使用mysql
    • 8.3 项目建表初始化
    • 9.1 原生koa2实现JSONP
    • 9.2 koa jsonp中间件
  • 其他

    • 操作数据库
    • Session 与 Token
    • Cookie、Session、Token、JWT
    • Socket
完整面试题地址:
作者:程序员poetry
扫码关注作者公众号:「前端进阶之旅」 每天分享技术干货
前端进阶之旅公众号二维码

express+session实现简易身份认证|Nodejs专题系列

# express+session实现简易身份认证

30 秒速记

  • 套路:登录校验密码 → 服务端存 session → 浏览器只拿一个 session id 的 cookie → 后续请求凭它查人
  • 登录成功先 req.session.regenerate() 换新 id,防会话固定
  • 退出 = req.session.destroy() 删服务端记录 + res.clearCookie() 清浏览器
  • 默认的 MemoryStore 只能本地玩:重启就丢、会泄漏内存、多实例不共享,生产换 Redis 这类共享存储
  • cookie 配 httpOnly(默认就开)、secure、sameSite,写操作还要防 CSRF

express-session 做登录,本质是「数据放服务端,浏览器只拿一张号码牌」。 用户登录成功后,服务端把用户名写进 req.session,中间件负责生成一个随机的 session id、签名后通过 Set-Cookie 发给浏览器;之后每个请求带着这张号码牌来,服务端凭它找回会话数据,判断你是谁。我做这类功能会盯三件事:登录后要 regenerate 换号,退出要在服务端真删,生产环境的 store 必须是多实例共享的。

理解「express+session实现简易身份认证」时,要先明确输入、运行阶段和可观察输出。这里的交互实验会分别执行正常路径与失败路径,并把 Node.js 的关键状态变化和同屏代码对应起来;不能只记命令名称。

工程中还要验证退出码、资源清理和异常输入。属于 security 场景的配置应保持最小可复现,并在开发环境与 CI 中使用相同命令复跑,避免把平台差异或隐式默认值带到线上。

面试官追问

追问 1登录成功后前端存个 isLogin = true,刷新就没了,这算身份认证吗?
参考回答

不算,那只是页面里的一个变量,后端根本不知道。认证状态得在服务端,每个受保护的接口都要从 req.session 里查一遍,前端那个变量顶多用来决定显示哪个按钮。

追问 2从一台机器扩到两台,用户登录后翻一页就变回未登录,为什么?
参考回答

会话存在第一台的内存或本地文件里,第二个请求被负载均衡打到另一台,那里查不到这个 session id。正解是换共享 store,比如 connect-redis;nginx 的 ip_hash 粘性会话能临时止血,但一台挂了那批用户还是全掉线。

追问 3登录接口返回成功,一跳转又回到登录页,你先看什么?
参考回答

先看网络面板:登录响应里有没有 Set-Cookie,下一个请求有没有把它带上。没带的话常见原因是 secure: true 但走的是 HTTP,或者跨域请求没开 credentials。带了还不行,再看服务端 store 里有没有这条记录。

追问 4登录成功为什么要调 regenerate,直接往 req.session 里写用户名不行吗?
参考回答

不换 id 会有会话固定攻击:攻击者先拿一个自己的 session id 塞给受害者,受害者用它登录后,攻击者手里那个 id 也就变成已登录了。regenerate 会作废旧 id、发一个新的,这一步很便宜,没理由省。

# 环境初始化

30 秒速记

  • express -e:用 express-generator 生成骨架,-e 表示模板用 EJS
  • npm install 装骨架自带的依赖,脚手架本身不帮你装
  • npm install express-session session-file-store:会话中间件 + 把会话存成本地文件的 store
  • npm 5 以后 --save 是默认行为,加不加都会写进 package.json
  • session-file-store 只适合单机演示,多实例生产换 connect-redis 之类的共享存储

环境初始化就三步:脚手架生成项目、装基础依赖、再装会话相关的两个包。 express -e 生成一个用 EJS 模板的 Express 骨架,这一步只建文件,不装依赖,所以紧接着要 npm install。然后装 express-session 负责会话逻辑,session-file-store 负责把会话数据写到项目下的 sessions 目录,方便你打开文件直接看里面存了什么。拿来学原理很直观,但上线别用文件存储,多台机器之间是不共享的。

首先,初始化项目

express -e
@前端进阶之旅: 代码已经复制到剪贴板

然后,安装依赖。

npm install
@前端进阶之旅: 代码已经复制到剪贴板

接着,安装session相关的包。

npm install --save express-session session-file-store
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1执行 express -e 提示命令不存在,怎么办?
参考回答

express 命令来自 express-generator,要先 npm i -g express-generator。现在更推荐不全局装,直接 npx express-generator -e,版本也不会跟别人机器上的对不上。

追问 2本地能跑,同事拉代码后启动报 Cannot find module 'express-session',问题在哪?
参考回答

八成是你装的时候没写进 package.json,只躺在自己的 node_modules 里。看一下 dependencies 有没有这一项,再确认 package-lock.json 一起提交了。在干净目录 npm ci 跑一遍,是最快的验证办法。

追问 3session-file-store 存的会话文件会越堆越多吗?
参考回答

它有个 reapInterval 参数,默认每小时清一次过期文件,所以不会无限增长。但这只是本机文件,进程多开几个、机器多加几台就各管各的,这也是它只适合演示 的原因。

追问 4这个演示项目要改成生产服务,依赖要换哪一个?
参考回答

把 session-file-store 换成 connect-redis 加一个 Redis 客户端,express-session 本身不用换。所有实例连同一个 Redis,会话自然共享,过期也交给 Redis 的 TTL 处理。

# session相关配置

30 秒速记

  • name:cookie 名,默认 connect.sid,改个名可以少暴露技术栈
  • secret:给 session id 签名的密钥,可以传数组做轮换,别硬编码在代码里
  • store:会话数据放哪,示例是本地文件,生产用 Redis
  • saveUninitialized: false:没往 session 写过东西就不落库、不发 cookie,匿名访客不产生垃圾会话
  • resave: false:会话没改就不回写,避免并发请求互相覆盖;store 支持 touch 时设 false 就行
  • cookie.maxAge 单位是毫秒,示例 10 * 1000 就是 10 秒,方便看过期效果

这段配置决定了四件事:cookie 叫什么、拿什么签名、数据存哪、多久过期。 最容易被问的是 saveUninitialized 和 resave。saveUninitialized: false 的意思是用户没登录、你也没往 req.session 写过东西,就不创建会话,否则每个路过的访客都会生成一个会话文件;resave: false 是会话内容没变就不重新写回存储,两个并发请求都回写的话,后完成的那个可能把前一个的修改覆盖掉。示例里 maxAge 只有 10 秒,是故意为了演示过期,真实项目一般是小时或天级别。

配置如下,并不复杂,可以见代码注释,或者参考 官方文档。

var express = require('express');
var app = express();
var session = require('express-session');
var FileStore = require('session-file-store')(session);

var identityKey = 'skey';

app.use(session({
    name: identityKey,
    secret: 'chyingp',  // 用来对session id相关的cookie进行签名
    store: new FileStore(),  // 本地存储session(文本文件,也可以选择其他store,比如redis的)
    saveUninitialized: false,  // 是否自动保存未初始化的会话,建议false
    resave: false,  // 是否每次都重新保存会话,建议false
    cookie: {
        maxAge: 10 * 1000  // 有效期,单位是毫秒
    }
}));
@前端进阶之旅: 代码已经复制到剪贴板

面试官追问

追问 1公开首页没登录,每次访问都会多出一个会话文件,最可能是哪项配置的问题?
参考回答

saveUninitialized 被设成了 true,未初始化的会话也会被保存并下发 cookie。改回 false;如果还在产生,看看是不是有别的中间件往 req.session 里写了东西,比如记录访问来源。

追问 2用户反馈每隔 10 秒就要重新登录,服务端也没报错,怎么回事?
参考回答

cookie.maxAge 还是示例里的 10 * 1000,浏览器 10 秒后就把 cookie 扔了。改成业务需要的时长,同时让 store 的过期时间对齐;想要「有操作就续期」再加 rolling: true。

追问 3为了「保证不丢数据」想把 resave 改成 true,同意吗?
参考回答

不同意。它会让没改过的会话每次请求都回写一遍,store 压力变大,而且并发请求之间更容易互相覆盖。如果担心活跃用户的会话过期,看 store 是否实现了 touch,主流的都有,resave: false 也会刷新过期时间。

追问 4站点挂在 nginx 后面走 HTTPS,加了 cookie: { secure: true } 之后登录态就没了,为什么?
参考回答

nginx 到 Node 这段是 HTTP,express-session 认为当前不是安全连接,就不下发 cookie。要加 app.set('trust proxy', 1),让它信任 X-Forwarded-Proto 头,同时确认 nginx 真的设置了这个头。

追问 5secret 想定期更换,又不想让所有人立刻掉线,怎么配?
参考回答

secret 支持传数组,比如 ['new-secret', 'old-secret']。第一个用来签新 cookie,后面的只用来校验,老用户的 cookie 还能通过;过了会话有效期再把旧的删掉。密钥本身从环境变量读,别写在代码里。

# 实现登录/登出接口

30 秒速记

  • 登录:校验账号密码 → regenerate 换新 session id → 写 req.session.loginUser → 返回成功
  • 登出:destroy 删服务端会话 → clearCookie 清浏览器 → 重定向
  • 失败分支要分开:账号密码错 / 会话创建失败,返回不同的码
  • 登出最好用 POST,GET 会被预加载、图片标签触发,存在 CSRF 登出问题
  • 先写完 session 再响应;手动 redirect 之前遇到时序问题可以显式 req.session.save(cb)

登录接口干的事是「验明身份后换一张新号码牌再记上名字」,登出接口是「服务端撕掉档案,再让浏览器扔掉号码牌」。 登录这边的关键是认证成功后先 regenerate 再写用户信息,防止沿用登录前的 session id。登出这边很多人只做了一半:只清 cookie 的话服务端会话还活着,只 destroy 的话浏览器还会继续带着一个已经失效的 id。两步都做,响应才算干净。

← express+cookie_parser签名机制深入剖析https →

fe