注销后 SailsJS CSRF 不匹配并获得新的 /csrfToken

SailsJS CSRF mismatch after logout AND getting new /csrfToken

我正在创建单页应用程序。我已经创建了登录-注销操作,它们工作正常。但是如果用户注销并且不会在浏览器中刷新页面,他将无法再次登录,因为 "CSRF mismatch" 错误。

步骤:

1。在第一个页面加载时,csrf 是 view local:

<div class="app" id="app" data-csrf="<%= _csrf %>"></div>

2。用户使用此令牌成功登录:

420["post",{"method":"post","headers":{},"data":{"_csrf":"VHcT2F44-KhZMJmhcAVB1H69BgTMWMZji9_8","login":"alex","password":"123"},"url":"http://127.0.0.1:1337/login"}]
430[{"body":{"id":"560e5756cd01633407eea8be"},"headers":{cut headers},"statusCode":200}]

3。然后,用户使用此令牌注销:

421["post",{"method":"post","headers":{},"data":{"_csrf":"VHcT2F44-KhZMJmhcAVB1H69BgTMWMZji9_8"},"url":"http://127.0.0.1:1337/logout"}]
431[{"body":"ok","headers":{cut headers},"statusCode":200}]

4。如果他再次尝试登录,他将捕获 "CSRF mismatch" 错误,我预计:

422["post",{"method":"post","headers":{},"data":{"_csrf":"VHcT2F44-KhZMJmhcAVB1H69BgTMWMZji9_8","login":"alex","password":"123"},"url":"http://127.0.0.1:1337/login"}]
432[{"body":"CSRF mismatch","headers":{},"statusCode":403}]

5。我正在捕获此错误并按照 docs

中所述执行 /csrfToken 请求
423["get",{"method":"get","headers":{},"data":{},"url":"/csrfToken"}]
433[{"body":{"_csrf":"49C5OVUZ-6SIL_zW3g1NGI87ux6Mlp-UJj_w"},"headers":{cut headers},"statusCode":200}]

6.尝试使用新令牌再次登录:

424["post",{"method":"post","headers":{},"data":{"_csrf":"49C5OVUZ-6SIL_zW3g1NGI87ux6Mlp-UJj_w","login":"alex","password":"123"},"url":"http://127.0.0.1:1337/login"}]
434[{"body":"CSRF mismatch","headers":{},"statusCode":403}]

我可以重复步骤 5 和 6 得到相同的结果。

如果我刷新页面,我可以正确登录。 问题是,这是怎么回事?为什么第 6 步的令牌不匹配?

编辑:注销方法:

req.session.destroy();
return res.send("ok");

编辑 2:发送请求:

import socketIOClient from 'socket.io-client';
import sailsIOClient from 'sails.io.js';
var io = sailsIOClient(socketIOClient);

io.socket.post(form.action, serialize(form, {hash: true}), function (data, jwres){
...
});

TL;DR:如果您在套接字上执行所有操作,请使用 req.session.csrfSecret = null 而不是 req.session.destroy()


这里的问题是 Express sessions work. When you call .destroy() on one, it removes the entry for the current session ID (SID) in the sessions object that Express MemoryStore maintains. Normally that's fine because it will be regenerated on the next request, but that's only the next request that runs all of the Express middleware--and Socket requests to a Sails app don't do that, as anyone trying to use Passport with Sails out-of-the-box 会告诉你的方式。因此,下次您发出套接字请求(生成新的 CSRF 机密并获取新令牌)时,您实际上并没有连接到会话,新信息也不会被保存。

如果不是销毁整个会话,而是销毁用于生成 CSRF 令牌的 csrfSecret,那么下一个套接字请求仍将附加到会话中,新的秘密将被保存。您还需要清空任何其他使用户保持登录状态的会话变量。