diff --git a/HISTORY.md b/HISTORY.md index 727834eb..4145b4fd 100644 --- a/HISTORY.md +++ b/HISTORY.md @@ -1,6 +1,11 @@ unreleased ========== + * Methods are no longer enumerable on `req.session` object + +1.13.1 / 2016-01-29 +=================== + * deps: parseurl@~1.3.1 - perf: enable strict mode * deps: uid-safe@~2.1.0 diff --git a/README.md b/README.md index f81381f2..a93e351b 100644 --- a/README.md +++ b/README.md @@ -1,58 +1,31 @@ # express-session -[![NPM Version][npm-image]][npm-url] -[![NPM Downloads][downloads-image]][downloads-url] -[![Build Status][travis-image]][travis-url] -[![Test Coverage][coveralls-image]][coveralls-url] -[![Gratipay][gratipay-image]][gratipay-url] - -## Installation - -```bash -$ npm install express-session +## 安装 +```js + $ npm install express-session ``` - ## API - -```js -var session = require('express-session') ``` + var session = require('express-session') +``` +#### session(配置) +使用相应的配置来创建一个session中间件 -### session(options) - -Create a session middleware with the given `options`. - -**Note** Session data is _not_ saved in the cookie itself, just the session ID. -Session data is stored server-side. - -**Warning** The default server-side session storage, `MemoryStore`, is _purposely_ -not designed for a production environment. It will leak memory under most -conditions, does not scale past a single process, and is meant for debugging and -developing. - -For a list of stores, see [compatible session stores](#compatible-session-stores). - -#### Options - -`express-session` accepts these properties in the options object. - -##### cookie - -Settings for the session ID cookie. See the "Cookie options" section below for -more information on the different values. - -The default value is `{ path: '/', httpOnly: true, secure: false, maxAge: null }`. +**提示** 除了session ID之外,session的数据*不会*自己储存到cookie中,session的数据会被存在服务器端 -##### genid +**警告** 在服务器端session故意默认储存在内存中,这不是为了生产环境而设计的.这样在大多数情况下会泄露内存,does not scale past a single process, and is meant for debugging and developing. -Function to call to generate a new session ID. Provide a function that returns -a string that will be used as a session ID. The function is given `req` as the -first argument if you want to use some value attached to `req` when generating -the ID. +更多的储存列表,详情请看: [compatible session stores](#compatible-session-stores) +#### 配置 +`express-session`在配置对象中可以接受这些属性 +###### cookie +设置cookie中的session ID.cookie更多不同参数的信息,请参考下面"cookie配置"小节,其默认的参数为`{ path: '/', httpOnly: true, secure: false, maxAge: null }` +###### genid +用来生成一个新的session ID的函数,提供一个返回通常用来做session ID的字符串的方法.当生成ID时,你如果想将某些值赋值给`req`,那么`req`作为该方法的第一个参数. -The default value is a function which uses the `uid-safe` library to generate IDs. +该默认值是一个使用`uid-safe`依赖库生成ID的函数. -**NOTE** be careful to generate unique IDs so your sessions do not conflict. +**提示** 注意生成唯一的ID,这样你的session才不会产生冲突 ```js app.use(session({ @@ -65,77 +38,47 @@ app.use(session({ ##### name -The name of the session ID cookie to set in the response (and read from in the -request). +session ID的cookie名可以在设置在响应头中(可以在请求头中读取). -The default value is `'connect.sid'`. +默认值是 `'connect.sid'`. -**Note** if you have multiple apps running on the same hostname (this is just -the name, i.e. `localhost` or `127.0.0.1`; different schemes and ports do not -name a different hostname), then you need to separate the session cookies from -each other. The simplest method is to simply set different `name`s per app. +**提示**如果你有多个app运行在同一个主机名上(只是主机名相同,比如`localhost`或者`127.0.0.1`;如果有不同的方案和端口的话,就没有必要命名不同的主机名了),这时你需要区分每一个session cookie了.最简单的方法是为每一个app设置一个不同的名称. ##### proxy -Trust the reverse proxy when setting secure cookies (via the "X-Forwarded-Proto" -header). +当设置了安全的cookie后,可以充分相信反向代理(可以通过"X-Forwarded-Proto"头) -The default value is `undefined`. +默认值 `undefined`. - - `true` The "X-Forwarded-Proto" header will be used. - - `false` All headers are ignored and the connection is considered secure only - if there is a direct TLS/SSL connection. - - `undefined` Uses the "trust proxy" setting from express + - `true` 使用 "X-Forwarded-Proto" 头 + - `false` 连接都只考虑安全性,所有的头都会被忽略 + 如果这是一个TLS/SSL连接的话 + - `undefined` 使用express中设置的"trust proxy" ##### resave -Forces the session to be saved back to the session store, even if the session -was never modified during the request. Depending on your store this may be -necessary, but it can also create race conditions where a client makes two -parallel requests to your server and changes made to the session in one -request may get overwritten when the other request ends, even if it made no -changes (this behavior also depends on what store you're using). +即使在请求中session没有进行任何修改,也会强制session重新存储一遍. +取决于你的存储这是非常有必要的,但是它会产生一个竞争的情况,当一个客户端向你的服务器发送两条并行的请求时,一个请求中session发生改变时,当另一个请求结束时,这个session可能会被重写,即使这个session没有做任何修改,也可能会被重写(这种情况也取决于你使用的存储). -The default value is `true`, but using the default has been deprecated, -as the default will change in the future. Please research into this setting -and choose what is appropriate to your use-case. Typically, you'll want -`false`. +默认值是 `true`,但是这个默认值已经被弃用了,这个默认值在之后会被修改.请在研究这个设置后,根据你的使用情况来选择.通常情况下,你会选择`false`. -How do I know if this is necessary for my store? The best way to know is to -check with your store if it implements the `touch` method. If it does, then -you can safely set `resave: false`. If it does not implement the `touch` -method and your store sets an expiration date on stored sessions, then you -likely need `resave: true`. +那我怎么知道,这个是否对我的存储有必要呢?最好的方式是检查你的存储是否有`touch`这个方法.如果有,你可以安全设置`resave:false`.如果没有`touch`这个方法,你的储存会在被存储的session上设置一个过期时间,然后你可能需要`resave:true`. ##### rolling -Force a session identifier cookie to be set on every response. The expiration -is reset to the original [`maxAge`](#cookiemaxage), resetting the expiration -countdown. +会在每一个响应上,强制session设置一个cookie识别码.过期时间会被重置为original [`maxAge`](#cookiemaxage),并且重置倒计时. -The default value is `false`. +默认值是 `false`. -**Note** When this option is set to `true` but the `saveUninitialized` option is -set to `false`, the cookie will not be set on a response with an uninitialized -session. +**提示** 当这个被设置为`true`,但是`saveUninitialized`设置为`false`时,一个响应的session没有被初始化,cookie是不会被设置的. ##### saveUninitialized -Forces a session that is "uninitialized" to be saved to the store. A session is -uninitialized when it is new but not modified. Choosing `false` is useful for -implementing login sessions, reducing server storage usage, or complying with -laws that require permission before setting a cookie. Choosing `false` will also -help with race conditions where a client makes multiple parallel requests -without a session. +强制将未初始化的session存储到内存中,未初始化的session是指一个全新的session且没有被修改过的.在使用登录session,减少服务器内存的使用,或者遵守在设置cookie前获取许可的规范时,将其设置为`false`是一个不错的选择.而且还能对客户端发送多个没有session请求的所形成竞争情况有所帮助. -The default value is `true`, but using the default has been deprecated, as the -default will change in the future. Please research into this setting and -choose what is appropriate to your use-case. +默认值是`true`,但是使用默认值已经被弃用,默认值在之后也将被修改,请研究这个设置之后,根据你的使用情况来选择 -**Note** if you are using Session in conjunction with PassportJS, Passport -will add an empty Passport object to the session for use after a user is -authenticated, which will be treated as a modification to the session, causing -it to be saved. +**提示** 如果你与PassportJS结合使用session的话,在用户认证之后,Passport会增加一个空的Passport对象在session中.这会默认认为session已经被修改,而造成这个session被存储的情况. ##### secret @@ -412,96 +355,128 @@ The following modules implement a session store that is compatible with this module. Please make a PR to add additional modules :) [![★][cassandra-store-image] cassandra-store][cassandra-store-url] An Apache Cassandra-based session store. + [cassandra-store-url]: https://www.npmjs.com/package/cassandra-store [cassandra-store-image]: https://img.shields.io/github/stars/webcc/cassandra-store.svg?label=%E2%98%85 [![★][cluster-store-image] cluster-store][cluster-store-url] A wrapper for using in-process / embedded stores - such as SQLite (via knex), leveldb, files, or memory - with node cluster (desirable for Raspberry Pi 2 and other multi-core embedded devices). + [cluster-store-url]: https://www.npmjs.com/package/cluster-store [cluster-store-image]: https://img.shields.io/github/stars/coolaj86/cluster-store.svg?label=%E2%98%85 +[![★][connect-azuretables-image] connect-azuretables][connect-azuretables-url] An [Azure Table Storage](https://azure.microsoft.com/en-gb/services/storage/tables/)-based session store. + +[connect-azuretables-url]: https://www.npmjs.com/package/connect-azuretables +[connect-azuretables-image]: https://img.shields.io/github/stars/mike-goodwin/connect-azuretables.svg?label=%E2%98%85 + [![★][connect-couchbase-image] connect-couchbase][connect-couchbase-url] A [couchbase](http://www.couchbase.com/)-based session store. + [connect-couchbase-url]: https://www.npmjs.com/package/connect-couchbase [connect-couchbase-image]: https://img.shields.io/github/stars/christophermina/connect-couchbase.svg?label=%E2%98%85 [![★][connect-dynamodb-image] connect-dynamodb][connect-dynamodb-url] A DynamoDB-based session store. + [connect-dynamodb-url]: https://github.com/ca98am79/connect-dynamodb [connect-dynamodb-image]: https://img.shields.io/github/stars/ca98am79/connect-dynamodb.svg?label=%E2%98%85 [![★][connect-mssql-image] connect-mssql][connect-mssql-url] A SQL Server-based session store. + [connect-mssql-url]: https://www.npmjs.com/package/connect-mssql [connect-mssql-image]: https://img.shields.io/github/stars/patriksimek/connect-mssql.svg?label=%E2%98%85 [![★][connect-monetdb-image] connect-monetdb][connect-monetdb-url] A MonetDB-based session store. + [connect-monetdb-url]: https://www.npmjs.com/package/connect-monetdb [connect-monetdb-image]: https://img.shields.io/github/stars/MonetDB/npm-connect-monetdb.svg?label=%E2%98%85 [![★][connect-mongo-image] connect-mongo][connect-mongo-url] A MongoDB-based session store. + [connect-mongo-url]: https://www.npmjs.com/package/connect-mongo [connect-mongo-image]: https://img.shields.io/github/stars/kcbanner/connect-mongo.svg?label=%E2%98%85 [![★][connect-mongodb-session-image] connect-mongodb-session][connect-mongodb-session-url] Lightweight MongoDB-based session store built and maintained by MongoDB. + [connect-mongodb-session-url]: https://www.npmjs.com/package/connect-mongodb-session [connect-mongodb-session-image]: https://img.shields.io/github/stars/mongodb-js/connect-mongodb-session.svg?label=%E2%98%85 [![★][connect-pg-simple-image] connect-pg-simple][connect-pg-simple-url] A PostgreSQL-based session store. + [connect-pg-simple-url]: https://www.npmjs.com/package/connect-pg-simple [connect-pg-simple-image]: https://img.shields.io/github/stars/voxpelli/node-connect-pg-simple.svg?label=%E2%98%85 [![★][connect-redis-image] connect-redis][connect-redis-url] A Redis-based session store. + [connect-redis-url]: https://www.npmjs.com/package/connect-redis [connect-redis-image]: https://img.shields.io/github/stars/tj/connect-redis.svg?label=%E2%98%85 [![★][connect-memcached-image] connect-memcached][connect-memcached-url] A memcached-based session store. + [connect-memcached-url]: https://www.npmjs.com/package/connect-memcached [connect-memcached-image]: https://img.shields.io/github/stars/balor/connect-memcached.svg?label=%E2%98%85 [![★][connect-session-knex-image] connect-session-knex][connect-session-knex-url] A session store using [Knex.js](http://knexjs.org/), which is a SQL query builder for PostgreSQL, MySQL, MariaDB, SQLite3, and Oracle. + [connect-session-knex-url]: https://www.npmjs.com/package/connect-session-knex [connect-session-knex-image]: https://img.shields.io/github/stars/llambda/connect-session-knex.svg?label=%E2%98%85 [![★][connect-session-sequelize-image] connect-session-sequelize][connect-session-sequelize-url] A session store using [Sequelize.js](http://sequelizejs.com/), which is a Node.js / io.js ORM for PostgreSQL, MySQL, SQLite and MSSQL. + [connect-session-sequelize-url]: https://www.npmjs.com/package/connect-session-sequelize [connect-session-sequelize-image]: https://img.shields.io/github/stars/mweibel/connect-session-sequelize.svg?label=%E2%98%85 +[![★][express-mysql-session-image] express-mysql-session][express-mysql-session-url] A session store using native +[MySQL](https://www.mysql.com/) via the [node-mysql](https://github.com/felixge/node-mysql) module. + +[express-mysql-session-url]: https://www.npmjs.com/package/express-mysql-session +[express-mysql-session-image]: https://img.shields.io/github/stars/chill117/express-mysql-session.svg?label=%E2%98%85 + [![★][connect-sqlite3-image] connect-sqlite3][connect-sqlite3-url] A [SQLite3](https://github.com/mapbox/node-sqlite3) session store modeled after the TJ's `connect-redis` store. + [connect-sqlite3-url]: https://www.npmjs.com/package/connect-sqlite3 [connect-sqlite3-image]: https://img.shields.io/github/stars/rawberg/connect-sqlite3.svg?label=%E2%98%85 [![★][express-nedb-session-image] express-nedb-session][express-nedb-session-url] A NeDB-based session store. + [express-nedb-session-url]: https://www.npmjs.com/package/express-nedb-session [express-nedb-session-image]: https://img.shields.io/github/stars/louischatriot/express-nedb-session.svg?label=%E2%98%85 [![★][level-session-store-image] level-session-store][level-session-store-url] A LevelDB-based session store. + [level-session-store-url]: https://www.npmjs.com/package/level-session-store [level-session-store-image]: https://img.shields.io/github/stars/scriptollc/level-session-store.svg?label=%E2%98%85 [![★][mssql-session-store-image] mssql-session-store][mssql-session-store-url] A SQL Server-based session store. + [mssql-session-store-url]: https://www.npmjs.com/package/mssql-session-store [mssql-session-store-image]: https://img.shields.io/github/stars/jwathen/mssql-session-store.svg?label=%E2%98%85 [![★][nedb-session-store-image] nedb-session-store][nedb-session-store-url] An alternate NeDB-based (either in-memory or file-persisted) session store. + [nedb-session-store-url]: https://www.npmjs.com/package/nedb-session-store [nedb-session-store-image]: https://img.shields.io/github/stars/JamesMGreene/nedb-session-store.svg?label=%E2%98%85 [![★][sequelstore-connect-image] sequelstore-connect][sequelstore-connect-url] A session store using [Sequelize.js](http://sequelizejs.com/). + [sequelstore-connect-url]: https://www.npmjs.com/package/sequelstore-connect [sequelstore-connect-image]: https://img.shields.io/github/stars/MattMcFarland/sequelstore-connect.svg?label=%E2%98%85 [![★][session-file-store-image] session-file-store][session-file-store-url] A file system-based session store. + [session-file-store-url]: https://www.npmjs.com/package/session-file-store [session-file-store-image]: https://img.shields.io/github/stars/valery-barysok/session-file-store.svg?label=%E2%98%85 [![★][session-rethinkdb-image] session-rethinkdb][session-rethinkdb-url] A [RethinkDB](http://rethinkdb.com/)-based session store. + [session-rethinkdb-url]: https://www.npmjs.com/package/session-rethinkdb [session-rethinkdb-image]: https://img.shields.io/github/stars/llambda/session-rethinkdb.svg?label=%E2%98%85 ## Example -A simple example using `express-session` to store page views for a user. +一个使用`express-session`的简单例子,来演示用户存储一个页面视图. ```js var express = require('express') diff --git a/package.json b/package.json index 8b945f2e..b9e15281 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "express-session", - "version": "1.13.0", + "version": "1.13.1", "description": "Simple session middleware for Express", "author": "TJ Holowaychuk (http://tjholowaychuk.com)", "contributors": [ diff --git a/session/session.js b/session/session.js index c3c0f15a..2eacde60 100644 --- a/session/session.js +++ b/session/session.js @@ -44,9 +44,9 @@ function Session(req, data) { * @api public */ -Session.prototype.touch = function(){ +defineMethod(Session.prototype, 'touch', function touch() { return this.resetMaxAge(); -}; +}); /** * Reset `.maxAge` to `.originalMaxAge`. @@ -55,10 +55,10 @@ Session.prototype.touch = function(){ * @api public */ -Session.prototype.resetMaxAge = function(){ +defineMethod(Session.prototype, 'resetMaxAge', function resetMaxAge() { this.cookie.maxAge = this.cookie.originalMaxAge; return this; -}; +}); /** * Save the session data with optional callback `fn(err)`. @@ -68,10 +68,10 @@ Session.prototype.resetMaxAge = function(){ * @api public */ -Session.prototype.save = function(fn){ +defineMethod(Session.prototype, 'save', function save(fn) { this.req.sessionStore.set(this.id, this, fn || function(){}); return this; -}; +}); /** * Re-loads the session data _without_ altering @@ -85,7 +85,7 @@ Session.prototype.save = function(fn){ * @api public */ -Session.prototype.reload = function(fn){ +defineMethod(Session.prototype, 'reload', function reload(fn) { var req = this.req , store = this.req.sessionStore; store.get(this.id, function(err, sess){ @@ -95,7 +95,7 @@ Session.prototype.reload = function(fn){ fn(); }); return this; -}; +}); /** * Destroy `this` session. @@ -105,11 +105,11 @@ Session.prototype.reload = function(fn){ * @api public */ -Session.prototype.destroy = function(fn){ +defineMethod(Session.prototype, 'destroy', function destroy(fn) { delete this.req.session; this.req.sessionStore.destroy(this.id, fn); return this; -}; +}); /** * Regenerate this request's session. @@ -119,7 +119,24 @@ Session.prototype.destroy = function(fn){ * @api public */ -Session.prototype.regenerate = function(fn){ +defineMethod(Session.prototype, 'regenerate', function regenerate(fn) { this.req.sessionStore.regenerate(this.req, fn); return this; +}); + +/** + * Helper function for creating a method on a prototype. + * + * @param {Object} obj + * @param {String} name + * @param {Function} fn + * @private + */ +function defineMethod(obj, name, fn) { + Object.defineProperty(obj, name, { + configurable: true, + enumerable: false, + value: fn, + writable: true + }); }; diff --git a/test/session.js b/test/session.js index 682cb8d0..35f20de2 100644 --- a/test/session.js +++ b/test/session.js @@ -1420,6 +1420,24 @@ describe('session()', function(){ }); }) + it('should not have enumerable methods', function (done) { + var app = express() + .use(session({ secret: 'keyboard cat', cookie: { maxAge: min }})) + .use(function(req, res, next) { + req.session.foo = 'foo'; + req.session.bar = 'bar'; + var keys = []; + for (var key in req.session) { + keys.push(key); + } + res.end(keys.sort().join(',')); + }); + + request(app) + .get('/') + .expect(200, 'bar,cookie,foo', done); + }); + describe('.destroy()', function(){ it('should destroy the previous session', function(done){ var app = express()