🌐 Nodejs.cn

cookie-session 中间件

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

🌐 Simple cookie-based session middleware.

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

🌐 A user session can be stored in two main ways with cookies: on the server or on the client. This module stores the session data on the client within a cookie, while a module like express-session stores only a session identifier on the client within a cookie and stores the session data on the server, typically in a database.

以下几点可以帮助你选择使用哪一个:

🌐 The following points can help you choose which to use:

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

注意 这个模块不会加密 cookie 中的会话内容,只提供签名以防篡改。客户端可以通过检查 cookie 的值来读取会话数据。不应在 req.session 中设置机密数据,除非进行了加密,或者应使用服务器端会话。

注意 该模块无法防止会话重放,因为设置的过期时间仅针对 cookie;如果这是你应用关注的问题,你可以将过期日期存储在 req.session 对象中,并在服务器上进行验证,并根据你的应用需求实现任何其他延长会话的逻辑。

安装

🌐 Install

这是一个可以通过npm注册表获取的Node.js模块。安装可以使用npm install命令完成:

🌐 This is a Node.js module available through the npm registry. Installation is done using the npm install command:

Terminal window
npm install cookie-session

Note

cookie-session 不包含其自身的 TypeScript 类型定义。如果你使用 TypeScript,还需要作为开发依赖从 DefinitelyTyped 安装社区维护的类型:

Terminal window
npm install --save-dev @types/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,该属性提供一个表示已加载会话的对象。如果请求中未提供有效会话,则此会话为新会话;否则为从请求中加载的会话。

🌐 Create a new cookie session middleware with the provided options. This middleware will attach the property session to req, which provides an object representing the loaded session. This session is either a new session if no valid session was provided in the request, or a loaded session from the request.

如果 req.session 的内容被更改,中间件会自动向响应添加 Set-Cookie 头。注意,除非会话中有内容,否则响应中不会有 Set-Cookie 头(因此也不会为特定用户创建会话),所以一旦你有要为会话存储的标识信息,就务必尽快向 req.session 添加内容。

🌐 The middleware will automatically add a Set-Cookie header to the response if the contents of req.session were altered. Note that no Set-Cookie header will be in the response (and thus no session created for a specific user) unless there are contents in the session, so be sure to add something to req.session as soon as you have identifying information to store for the session.

选项

🌐 Options

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

🌐 Cookie session accepts these properties in the options object.

name

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

🌐 The name of the cookie to set, defaults to session.

keys

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

🌐 The list of keys to use to sign & verify cookie values, or a configured Keygrip instance. Set cookies are always signed with keys[0], while the other keys are valid for verification, allowing for key rotation. If a Keygrip instance is provided, it can be used to change signature parameters like the algorithm of the signature.

secret

keys 未提供时,将用作单个键的字符串。

🌐 A string which will be used as single key if keys is not provided.

🌐 Cookie Options

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

🌐 Other options are passed to cookies.get() and cookies.set() allowing you to control security, domain, path, and signing among other settings.

这些选项还可以包含以下任何内容(完整列表请参见cookies 模块文档

🌐 The options can also contain any of the following (for the full list, see cookies module documentation:

  • maxAge:一个表示从 Date.now() 到到期的毫秒数的数字
  • expires:一个 Date 对象,表示 cookie 的过期日期(默认在会话结束时过期)。
  • path:一个表示 cookie 路径的字符串(默认值为 /)。
  • domain:一个表示 cookie 域的字符串(无默认值)。
  • partitioned:一个布尔值,表示是否在 Chrome 中为 CHIPS 更新 分区 cookie(默认值为 false)。如果为 true,嵌入网站的 Cookies 将被分区,并且只能从创建它的相同顶层网站读取。
  • priority:指示 Cookie 优先级的字符串。可以设置为 'low''medium''high'
  • 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

表示给定请求的会话。

🌐 Represents the session for the given request.

.isChanged

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

🌐 Is true if the session has been changed during the request.

.isNew

如果会话是新的,则为 true

🌐 Is true if the session is new.

.已填充

🌐 .isPopulated

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

🌐 Determine if the session has been populated with data or is empty.

req.sessionOptions

表示当前请求的会话选项。这些选项是中间件构建时提供内容的浅拷贝,可以更改以在每个请求的基础上改变 cookie 设置行为。

🌐 Represents the session options for the current request. These options are a shallow clone of what was provided at middleware construction and can be altered to change cookie setting behavior on a per-request basis.

销毁会话

🌐 Destroying a session

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

🌐 To destroy a session simply set it to null:

req.session = null;

保存会话

🌐 Saving a session

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

🌐 Since the entire contents of the session is kept in a client-side cookie, the session is “saved” by writing a cookie out in a Set-Cookie response header. This is done automatically if there has been a change made to the session when the Node.js response headers are being written to the client and the session was not destroyed.

例子

🌐 Examples

简单视图计数器示例

🌐 Simple view counter example

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);

每用户固定最大寿命

🌐 Per-user sticky max age

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 ...

延长会话过期时间

🌐 Extending the session expiration

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

🌐 This module does not send a Set-Cookie header if the contents of the session have not changed. This means that to extend the expiration of a session in the user’s browser (in response to user activity, for example) some kind of modification to the session needs be made.

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 ...

使用自定义签名算法

🌐 Using a custom signature algorithm

此示例展示了创建一个自定义的 Keygrip 实例作为 keys 选项,以提供密钥和额外的签名配置。

🌐 This example shows creating a custom Keygrip instance as the keys option to provide keys and additional signature configuration.

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 ...

使用限制

🌐 Usage Limitations

🌐 Max Cookie Size

因为整个会话对象被编码并存储在 cookie 中,所以有可能超过不同浏览器的最大 cookie 大小限制。 RFC6265 规范 建议浏览器 应该 允许

🌐 Because the entire session object is encoded and stored in a cookie, it is possible to exceed the maximum cookie size limits on different browsers. The RFC6265 specification recommends that a browser SHOULD allow

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

在实际操作中,这个限制在不同浏览器间略有差异。请参阅此处的 浏览器限制列表。一般来说,每个域名不要超过 4093 字节

🌐 In practice this limit differs slightly across browsers. See a list of browser limits here. As a rule of thumb don’t exceed 4093 bytes per domain.

如果你的会话对象足够大,以至于在编码后超过浏览器限制,通常情况下,浏览器将拒绝存储该 cookie。这将导致浏览器之后的请求要么 a) 没有任何会话信息,要么 b) 使用旧的、足够小以不超过 cookie 限制的会话信息。

🌐 If your session object is large enough to exceed a browser limit when encoded, in most cases the browser will refuse to store the cookie. This will cause the following requests from the browser to either a) not have any session information or b) use old session information that was small enough to not exceed the cookie limit.

如果你发现你的会话对象达到了这些限制,最好考虑是否应该从服务器上的数据库加载会话中的数据,而不是在每个请求中与浏览器进行传输。或者转向一种替代会话策略

🌐 If you find your session object is hitting these limits, it is best to consider if data in your session should be loaded from a database on the server instead of transmitted to/from the browser with every request. Or move to an alternative session strategy

许可证

🌐 License

MIT