仅限会话的 Express.js Cookie

24

http://www.javascriptkit.com/javatutors/cookie.shtml

与之不同的是,仅会话(Session-only)Cookie将信息存储在浏览器内存中,在浏览器会话期间可用。换句话说,存储在会话Cookie内的数据从存储时起一直可用,直到关闭浏览器。在此期间从页面到页面的跳转并不会擦除数据。

我如何使用Express.js实现这一点呢?


说“在相同域中从页面到页面”更正确吗? - grantwparks
https://dev59.com/pl_Va4cB1Zd3GeqPUYxM - abernier
6个回答

66

首先,那个网站是一个非常糟糕的去处。

现在进入问题。

什么是Session:

  • 数据存储在服务器端。
  • 发出包含ID的cookie。
  • 由于浏览器发送cookies,每次请求都会将此ID发送回服务器。
  • 现在服务器可以将cookie中的ID(通常称为Session ID或简称SID)与存储在服务器上的会话数据重新关联。

Express.js内置了对Session的支持

示例显示了什么:

  • 设置Express.js中间件
  • 使用第三方存储保存会话数据,在本例中为Redis(我认为这对你目前的问题来说有点过头了)

安装Redis需要一些工作,但也可以使用Express.js内置的内存存储:

var express = require('express');
var app = express.createServer();

var MemoryStore = require('connect/middleware/session/memory');
app.use(express.bodyDecoder());
app.use(express.cookieDecoder());
app.use(express.session({ store: new MemoryStore({ reapInterval: 60000 * 10 }) }));

app.get('/', function(req, res){
    req.session.visitCount = req.session.visitCount ? req.session.visitCount + 1 : 1;
    res.send('You have visited this page ' + req.session.visitCount + ' times');
});

app.listen(4000);
这将简单地记录您访问页面的次数,关闭浏览器后再次打开时仍将保留计数。 您可以在此处找到有关“MemoryStore”选项的更多信息,例如会话的最长生存时间等。此处

很多网站只有会话期cookie。甚至Gmail也是吗?“保持登录”复选框只在会话期内有效吗?因为我希望当浏览器关闭时用户被注销。因为它可以在共享计算机上访问,人们可能会忘记按注销按钮?我想创建一个“保持登录”的复选框,以便同时拥有两种类型的会话。这可行吗?非常感谢。 - Alfred
1
你的代码片段不是仅限于会话的cookie,因为当你关闭cookie时,它会记住计数而不是将计数器重新设置为零。但我认为我知道如何解决这个问题。 - Alfred
@Ivo,问题只涉及会话cookie! - Ustaman Sangat
1
为了保护Ivo,我从未听说过“仅会话”这个术语来描述cookie。正如他所描述的那样,会话通常是指由生成的cookie值键入的服务器维护的信息,对吧?这个问题与“如何在浏览器关闭时使cookie过期”不同吗? - grantwparks
这不是他所问的。 你可以将所有会话存储在浏览器中的已签名 cookie 中...那些声称能够实现此功能但实际上并不能的 NodeJS 包引起的混乱程度令人发指,这证明了大多数 NodeJS 开发人员缺乏基本知识。 - João Antunes
express-session 的 readme 中可以看到:“警告:默认的服务器端会话存储 MemoryStore 并不是为生产环境而设计的。在大多数情况下,它会泄漏内存,无法扩展到单个进程之外,并且仅适用于调试和开发。有关存储列表,请参见兼容的会话存储。” - Mythos

11
以下是我想要的内容(差不多)。当我关闭浏览器时,信息就消失了。
var express = require('express');
var app = express.createServer();

var MemoryStore = require('connect/middleware/session/memory');
app.use(express.bodyDecoder());
app.use(express.cookieDecoder());

app.get('/remember', function(req, res) {
    res.cookie('rememberme', 'yes', { expires: new Date() - 1, httpOnly: true });
});

app.get('/', function(req, res){
    res.send('remember: ' + req.cookies.rememberme);
});

app.listen(4000, '127.0.0.1');

它还应该具备某种形式的服务器端验证! - Alfred
对于服务器端验证,我只需要像Ivo上面的示例一样添加req.session即可! - Alfred

7
app.use(express.session({cookie: { path: '/', httpOnly: true, maxAge: null }, secret:'eeuqram'}));

上述代码适用于IE8、Firefox和Chrome浏览器。重要的部分是maxAge:null

你可以创建一个新的问题(而不是猜测)。 - Alfred
@Alfred,https://dev59.com/XF_Va4cB1Zd3GeqPRTkK - Ustaman Sangat

2
app.get('/remember', function(req, res) {
   res.cookie('rememberme', 'yes', { expires: 0, httpOnly: true });
 });

这将设置会话cookie。在浏览器关闭时,它将被删除!

1

以下是使用 Express.js 的 Alfred's answer 的更新代码。

    var express = require('express');
    var app = express.createServer();

    var MemoryStore = require('/home/node/node_modules/connect/lib/middleware/session/memory');
    app.use(express.bodyParser());
    app.use(express.cookieParser());
    app.use(express.session({
        key: 'some-key',
        secret: 'some-We1rD sEEEEEcret!',
        store: new MemoryStore({ reapInterval: 60000 * 10 })
    }));

   app.get('/', function(req, res) {
       req.session.visitCount = req.session.visitCount ? req.session.visitCount + 1 : 1;
       res.send('You have visited this page ' + req.session.visitCount + ' times');
   });

   app.listen(4000);

他不想要一个MemoryStore - 他希望浏览器处理它。 - João Antunes

0

我知道这是一个老问题,但我还是要添加一个答案,因为这里的所有答案似乎都已经过时、存在安全漏洞或者完全错误。

截至目前,express默认使用MemoryStore,您不需要显式处理它。

此外,截至目前,express-session的官方自述页面在开头有一个醒目的警告,不要将MemoryStore用作生产环境的会话存储,引用如下:

警告 默认的服务器端会话存储MemoryStore,故意不设计用于生产环境。在大多数情况下,它会泄漏内存,无法扩展到单个进程之外,并且仅用于调试和开发。
有关存储列表,请参见兼容的会话存储

如果您想使用MongoDBStore进行会话存储,这里有一个简单的解决方案:connect-mongodb-session

import express from 'express';
import session from 'express-session';
import ConnectMongoDbSession from 'connect-mongodb-session';

const app = express();
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.use(session({
  secret: < COOKIE_SECRET >,
  name: 'sessionId', // Don't use the default name, see http://expressjs.com/en/advanced/best-practice-security.html
  cookie: {
    httpOnly: true,
    secure: true, // Remove this if you're not using HTTPS, but it will be a massive security flaw
    sameSite: 'strict',
  },
  store: getStore(),

  // Boilerplate options, see:
  // * https://www.npmjs.com/package/express-session#resave
  // * https://www.npmjs.com/package/express-session#saveuninitialized
  resave: true,
  saveUninitialized: true,
}));

function getStore() {
  const MongoDBStore = ConnectMongoDbSession(session);

  const store = new MongoDBStore({
    uri: < DATABASE_URI >,
    collection: < SESSION_COLLECTION_NAME >,
    connectionOptions: {
      useNewUrlParser: true,
      useUnifiedTopology: true,
    },
  });

  store.on('error', (error: any) => {
    console.error(error);
  });

  return store;
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接