NodeJS:在服务器呈现的视图和 React 应用程序之间共享会话的最佳方式是什么

NodeJS: What's the best way to share session between server-rendered views and React app

我有一个从服务器呈现页面的 NodeJS (Koa) 服务器应用程序,即 nunjucks/jade/etc。登录页面也是服务器呈现的。登录后,将创建 cookie。

现在我正在构建一个将嵌入到安全页面中的 React 应用程序(在用户登录后)。让 React 应用程序使用用户当前登录的会话向服务器发出安全 Http/Websocket 请求的最佳方式是什么?

目前,我正在将 sessionId 注入到加载 React 应用程序的服务器呈现页面的脚本标记中。所以...

服务器:

var session = require('koa-generic-session');
app.use(session({
    store: redisStore(...)
}));
app.use(function*(next) {
    this.state.sessionIdFromServer = this.sessionId;
    return yield next
});

客户:

<script>
var sessionId = {{sessionIdFromServer}};
</script>
...
<div id='app'> react app loads here </div>

然后我在我的客户端 HTTP/WebSocket 请求(特别是 websocket)中使用那个 sessionId 变量。

对于客户端发出的每个请求(在套接字的情况下传递 sessionId),服务器在完成请求之前基本上会检查 Redis 会话存储以查看该会话是否仍然有效(即未过期或注销)。

这是 feasible/secure-enough 方法吗?

对,我应该做的就是为你的 session 使用 cookie。这样任何前端 AJAX 调用(包括 WebSocket)都将在请求 headers.

中使用 cookie

在 cookie 上设置 HTTP Only 后,前端 JavaScript 无法修改(或访问)session cookie,但浏览器仍会在任何传出请求。

在我看来,这是使用 session id 最安全的方式,前端不需要首先知道 cookie 的存在。

如果 koa 中的 session 不再存在,您会自动知道用户也已注销。

我为此做了一个小例子(下面有一个Github link):

首先是index.js:

'use strict';

const session = require('koa-session');
const koa = require('koa');
const websockify = require('koa-websocket');
const route = require('koa-route');

const app = websockify(koa());

app.keys = ['some secret hurr'];
const sessionStore = session(app);

app.use(sessionStore);
app.ws.use(sessionStore);

app.use(route.all('/', function* (next) {
  // ignore favicon
  if (this.path === '/favicon.ico') return;

  let n = this.session.views || 0;
  this.session.views = ++n;
  yield next;
}));

app.ws.use(route.all('/', function* (next) {
  this.websocket.on('message', (message) => {
    let n = this.session.views || 0;
    this.session.views = ++n;

    if (message === 'ping') {
      // Return the amount of sessions (n) when the client sends ping
      this.websocket.send('pong ' + n);
    }
  });

  yield next;
}));

app.use(require('koa-static')('./public'));

app.listen(3000);
console.log('listening on port 3000');

然后是index.html:

<html>
  <script>
    var ws = new WebSocket("ws://localhost:3000/");

    ws.onopen = function() {
      // Sends a message
      ws.send("ping");  
    };

    ws.onmessage = function(e) {
      // Receives a message.
      alert(e.data);
    };

    ws.onclose = function() {
      alert("closed");
    };
  </script>
</html>

我已将所有这些放入一个工作示例中 on GitHub