黑人生命也是命。
支持平等正义倡议.

cookie-session

NPM Version NPM Downloads Build Status Test Coverage

基于 cookie 的简单会话中间件。

用户会话可以通过 cookie 以两种主要方式存储:在服务器上或在客户端上。此模块将会话数据存储在 cookie 中的客户端上,而 express-session 等模块仅将会话标识符存储在 cookie 中的客户端上,并将会话数据存储在服务器上,通常在数据库中。

以下几点可以帮助你选择使用哪种方式

  • cookie-session 不需要服务器端的任何数据库/资源,但会话数据的总大小不能超过浏览器的最大 cookie 大小。
  • cookie-session 可以简化某些负载平衡场景。
  • cookie-session 可用于存储“轻量级”会话,并包含一个标识符以查找数据库支持的辅助存储,以减少数据库查找。

注意此模块不会加密 cookie 中的会话内容,只会提供签名以防止篡改。客户端将能够通过检查 cookie 的值来读取会话数据。不应在未加密的情况下将秘密数据设置在 req.session 中,或者使用服务器端会话。

注意此模块不会阻止会话重放,因为设置的过期时间仅限于 cookie;如果这是你的应用程序所关注的问题,则可以将过期日期存储在 req.session 对象中并在服务器上验证它,并实现任何其他逻辑来根据应用程序需要延长会话。

安装

这是一个 Node.js 模块,可通过 npm 注册表 获得。安装使用 npm install 命令

$ npm install cookie-session

API

var cookieSession = require('cookie-session')
var express = require('express')

var app = express()

app.use(cookieSession({
  name: 'session',
  keys: [/* secret keys */],

  // Cookie Options
  maxAge: 24 * 60 * 60 * 1000 // 24 hours
}))

cookieSession(options)

使用提供的选项创建一个新的 cookie 会话中间件。此中间件会将属性 session 附加到 req,它提供表示已加载会话的对象。如果请求中没有提供有效的会话,则此会话是新会话;否则,它是从请求中加载的会话。

如果 req.session 的内容已更改,则中间件会自动将 Set-Cookie 标头添加到响应中。注意,除非会话中有内容,否则响应中不会有 Set-Cookie 标头(因此不会为特定用户创建会话),因此请务必在获得要为会话存储的识别信息后立即向 req.session 添加一些内容。

选项

Cookie 会话在选项对象中接受这些属性。

name

要设置的 cookie 的名称,默认为 session

keys

用于对 cookie 值进行签名和验证的密钥列表,或已配置的 Keygrip 实例。设置的 cookie 始终使用 keys[0] 进行签名,而其他密钥有效用于验证,从而允许密钥轮换。如果提供了 Keygrip 实例,则可以使用它来更改签名参数,例如签名的算法。

secret

如果未提供 keys,则将用作单个密钥的字符串。

其他选项传递给 cookies.get()cookies.set(),允许你控制安全性、域、路径和签名以及其他设置。

这些选项还可以包含以下任何选项(有关完整列表,请参阅 cookies 模块文档

  • maxAge:表示从 Date.now() 到到期时间的毫秒数。
  • expires:表示 cookie 到期日期的 Date 对象(默认情况下在会话结束时到期)。
  • path:表示 cookie 路径的字符串(默认值为 /)。
  • domain:表示 cookie 域的字符串(无默认值)。
  • sameSite:表示 cookie 是否为“同站点”cookie 的布尔值或字符串(默认值为 false)。这可以设置为 'strict''lax''none'true(映射到 'strict')。
  • secure:一个布尔值,表示 cookie 是否仅通过 HTTPS 发送(对于 HTTP,默认为 false,对于 HTTPS,默认为 true)。如果将其设置为 true 且 Node.js 并未直接通过 TLS 连接,请务必阅读如何 在代理后面设置 Express,否则 cookie 可能永远无法正确设置。
  • httpOnly:一个布尔值,表示 cookie 是否仅通过 HTTP(S) 发送,而不提供给客户端 JavaScript(默认为 true)。
  • signed:一个布尔值,表示 cookie 是否要签名(默认为 true)。
  • overwrite:一个布尔值,表示是否覆盖先前设置的同名 cookie(默认为 true)。

req.session

表示给定请求的会话。

.isChanged

如果在请求期间会话已更改,则为 true

.isNew

如果会话是新的,则为 true

.isPopulated

确定会话是否已填充数据或为空。

req.sessionOptions

表示当前请求的会话选项。这些选项是中间件构造时提供的选项的浅层克隆,可以对其进行更改,以逐个请求更改 cookie 设置行为。

销毁会话

要销毁会话,只需将其设置为 null

req.session = null

保存会话

由于会话的全部内容都保存在客户端 cookie 中,因此通过在 Set-Cookie 响应标头中写入 cookie 来“保存”会话。如果在将 Node.js 响应标头写入客户端时对会话进行了更改,并且会话未被销毁,则会自动执行此操作。

示例

简单的查看计数器示例

var cookieSession = require('cookie-session')
var express = require('express')

var app = express()

app.set('trust proxy', 1) // trust first proxy

app.use(cookieSession({
  name: 'session',
  keys: ['key1', 'key2']
}))

app.get('/', function (req, res, next) {
  // Update views
  req.session.views = (req.session.views || 0) + 1

  // Write response
  res.end(req.session.views + ' views')
})

app.listen(3000)

按用户粘滞的最大年龄

var cookieSession = require('cookie-session')
var express = require('express')

var app = express()

app.set('trust proxy', 1) // trust first proxy

app.use(cookieSession({
  name: 'session',
  keys: ['key1', 'key2']
}))

// This allows you to set req.session.maxAge to let certain sessions
// have a different value than the default.
app.use(function (req, res, next) {
  req.sessionOptions.maxAge = req.session.maxAge || req.sessionOptions.maxAge
  next()
})

// ... your logic here ...

延长会话过期时间

如果会话内容未更改,此模块将不会发送 Set-Cookie 标头。这意味着要延长用户浏览器中会话的过期时间(例如,响应用户活动),需要对会话进行某种修改。

var cookieSession = require('cookie-session')
var express = require('express')

var app = express()

app.use(cookieSession({
  name: 'session',
  keys: ['key1', 'key2']
}))

// Update a value in the cookie so that the set-cookie will be sent.
// Only changes every minute so that it's not sent with every request.
app.use(function (req, res, next) {
  req.session.nowInMinutes = Math.floor(Date.now() / 60e3)
  next()
})

// ... your logic here ...

使用自定义签名算法

此示例展示了如何创建自定义 Keygrip 实例作为 keys 选项,以提供密钥和附加签名配置。

var cookieSession = require('cookie-session')
var express = require('express')
var Keygrip = require('keygrip')

var app = express()

app.use(cookieSession({
  name: 'session',
  keys: new Keygrip(['key1', 'key2'], 'SHA384', 'base64')
}))

// ... your logic here ...

使用限制

由于整个会话对象都经过编码并存储在 Cookie 中,因此可能会超过不同浏览器上的最大 Cookie 大小限制。 RFC6265 规范 建议浏览器允许

每个 Cookie 至少 4096 字节(按 Cookie 名称、值和属性的长度总和计算)

实际上,此限制在不同浏览器中略有不同。请参阅此处 浏览器限制列表。经验法则是每个域不超过 4093 字节

如果会话对象大到足以在编码后超过浏览器限制,则大多数情况下浏览器将拒绝存储 Cookie。这会导致浏览器发出的后续请求 a) 没有任何会话信息或 b) 使用足够小以不超过 Cookie 限制的旧会话信息。

如果你发现会话对象达到了这些限制,最好考虑是否应从服务器上的数据库加载会话中的数据,而不是在每次请求时都与浏览器传输数据。或者迁移到 备选会话策略

许可证

MIT