在 express.js 中为每个请求创建了多个会话
Multiple sessions created for every request in express.js
我在这里描述的问题发生在我的本地开发机器上,浏览器请求和应用程序之间没有任何代理。
我有几个 Node.js 微服务,它们共享用于管理会话的相同技术:
- Express 的最新版本
- express-session and connect-redis 用于会话管理
通常的流程是用户在身份验证应用程序中登录,然后被重定向到前端(一个 React 应用程序),该前端向后端微服务执行 CORS 请求,后者是 运行 一个 GraphQL 服务器。
这个问题与 the one described here 非常相似,即使我的配置略有不同(静态路由仅在 auth 应用程序中并在会话定义之前使用,false
到 resave
和 saveUninitialized
选项)。
两个 auth/backend 应用程序都有此配置:
const sessionOptions = {
store: new RedisStore({
client: redisClient,
disableTTL: true,
}),
secret: "123",
resave: false,
saveUninitialized: false,
proxy: false,
rolling: true,
cookie: {
domain: config.cookie.domain,
sameSite: config.cookie.sameSite,
maxAge: toTime(config.cookie.maxAge).ms(),
secure: config.cookie.secure,
},
};
app.use(session(sessionOptions));
// Configure passport middleware
app.use(passport.initialize());
app.use(passport.session());
后端应用有额外的 CORS 配置:
app.use(cors({
origin: "frontend_url",
credentials: true,
methods: ['GET', 'POST'],
}));
初始 Redis 状态:
127.0.0.1:6379> KEYS "*"
(empty list or set)
我转到登录页面并创建了一个会话:
127.0.0.1:6379> KEYS "*"
1) "sess:H5VTTBiNSQqu0Fsp2ZfSH2wBZtL4XEZh"
我登录了,会话仍然是一个,直到我被重定向到我的 React 应用程序,然后我得到六个新会话:
127.0.0.1:6379> KEYS "*"
1) "sess:NNWse-sp51fVRf6rlnsFpMlZO1gkPgYC"
2) "sess:ofQhH0iBbZOvsJBYMxwHjLL0DKxuFKfS"
3) "sess:XxsTGSoANPE5-fPYbwLmoCgvDho0NTnk"
4) "sess:9wFDQ3_RibJyEXEmJ_8gCxfnak4Uh0yP"
5) "sess:8khC8fgbtO53mJNilMhp88toIcsizxea"
6) "sess:jfQBWogefBr75IgZ5GykSgd5d3t3Mt_D"
7) "sess:H5VTTBiNSQqu0Fsp2ZfSH2wBZtL4XEZh"
无论我点击什么 link,它们的数量都会增加到 16,依此类推。我无法向我的后端发现任何不是发送会话 cookie 而是发送 OPTION 飞行前请求的请求。所以我尝试使用 my own configuration instead than CORS module,但没有任何改变。
如果我注销,显然只有与我的会话 cookie 匹配的原始会话会从 Redis 中删除,其余的(因为我已禁用 TTL 以拥有 "permanent" 会话)只是挂在那里。
同样明显的是,我不希望 Redis 充满无用的会话,但我找不到真正的问题所在。
有什么建议吗?
谢谢。
更新:如果我尝试使用自定义的内容修改 genid
函数,我会注意到不同的行为:
- 对于身份验证服务,我 return
null
如果我没有 req.body.username
定义 (${req.body.username}_${uuidv4()}
)。
- 对于后端服务,我每次都 return
null
。
对 auth 服务的第一个请求引发异常 invalid csrf
,因为可能无法在 Redis 中找到它,因为 genid
现在 returning null。第二个请求(假设您使用与之前相同的电子邮件并且登录成功)将我带到前端,这次我只能看到一个正在创建的会话。
显然,这不是一个正确的流程,但无论如何它在 Redis 中只创建一个会话是很奇怪的。
我 运行 几天前遇到了同样的问题!我已经设置了我的回购协议并分享了我的 link !它工作完美!请检查一下。
最后,我发现一些发送到我的身份验证服务的请求没有设置会话 cookie,对于某些路径甚至不应该使用它。
所以我定义了那些与会话相关的路径:
const sessionPaths = ['/path1', '/path2', ...];
app.use(sessionPaths, session(sessionOptions));
app.use(sessionPaths, passport.initialize());
app.use(sessionPaths, passport.session());
app.use(sessionPaths, csrf());
不确定这是否已完全解决,但鉴于您的布局顺序,您可能在会话处理程序之后有 cors 处理程序。当预检请求进入时,可能会为每个请求创建一个会话,因为没有发送会话 cookie 或凭据。简单的解决方法是将 cors 处理程序移动到会话处理程序之上。
我在这里描述的问题发生在我的本地开发机器上,浏览器请求和应用程序之间没有任何代理。 我有几个 Node.js 微服务,它们共享用于管理会话的相同技术:
- Express 的最新版本
- express-session and connect-redis 用于会话管理
通常的流程是用户在身份验证应用程序中登录,然后被重定向到前端(一个 React 应用程序),该前端向后端微服务执行 CORS 请求,后者是 运行 一个 GraphQL 服务器。
这个问题与 the one described here 非常相似,即使我的配置略有不同(静态路由仅在 auth 应用程序中并在会话定义之前使用,false
到 resave
和 saveUninitialized
选项)。
两个 auth/backend 应用程序都有此配置:
const sessionOptions = {
store: new RedisStore({
client: redisClient,
disableTTL: true,
}),
secret: "123",
resave: false,
saveUninitialized: false,
proxy: false,
rolling: true,
cookie: {
domain: config.cookie.domain,
sameSite: config.cookie.sameSite,
maxAge: toTime(config.cookie.maxAge).ms(),
secure: config.cookie.secure,
},
};
app.use(session(sessionOptions));
// Configure passport middleware
app.use(passport.initialize());
app.use(passport.session());
后端应用有额外的 CORS 配置:
app.use(cors({
origin: "frontend_url",
credentials: true,
methods: ['GET', 'POST'],
}));
初始 Redis 状态:
127.0.0.1:6379> KEYS "*"
(empty list or set)
我转到登录页面并创建了一个会话:
127.0.0.1:6379> KEYS "*"
1) "sess:H5VTTBiNSQqu0Fsp2ZfSH2wBZtL4XEZh"
我登录了,会话仍然是一个,直到我被重定向到我的 React 应用程序,然后我得到六个新会话:
127.0.0.1:6379> KEYS "*"
1) "sess:NNWse-sp51fVRf6rlnsFpMlZO1gkPgYC"
2) "sess:ofQhH0iBbZOvsJBYMxwHjLL0DKxuFKfS"
3) "sess:XxsTGSoANPE5-fPYbwLmoCgvDho0NTnk"
4) "sess:9wFDQ3_RibJyEXEmJ_8gCxfnak4Uh0yP"
5) "sess:8khC8fgbtO53mJNilMhp88toIcsizxea"
6) "sess:jfQBWogefBr75IgZ5GykSgd5d3t3Mt_D"
7) "sess:H5VTTBiNSQqu0Fsp2ZfSH2wBZtL4XEZh"
无论我点击什么 link,它们的数量都会增加到 16,依此类推。我无法向我的后端发现任何不是发送会话 cookie 而是发送 OPTION 飞行前请求的请求。所以我尝试使用 my own configuration instead than CORS module,但没有任何改变。 如果我注销,显然只有与我的会话 cookie 匹配的原始会话会从 Redis 中删除,其余的(因为我已禁用 TTL 以拥有 "permanent" 会话)只是挂在那里。 同样明显的是,我不希望 Redis 充满无用的会话,但我找不到真正的问题所在。 有什么建议吗? 谢谢。
更新:如果我尝试使用自定义的内容修改 genid
函数,我会注意到不同的行为:
- 对于身份验证服务,我 return
null
如果我没有req.body.username
定义 (${req.body.username}_${uuidv4()}
)。 - 对于后端服务,我每次都 return
null
。
对 auth 服务的第一个请求引发异常 invalid csrf
,因为可能无法在 Redis 中找到它,因为 genid
现在 returning null。第二个请求(假设您使用与之前相同的电子邮件并且登录成功)将我带到前端,这次我只能看到一个正在创建的会话。
显然,这不是一个正确的流程,但无论如何它在 Redis 中只创建一个会话是很奇怪的。
我 运行 几天前遇到了同样的问题!我已经设置了我的回购协议并分享了我的 link !它工作完美!请检查一下。
最后,我发现一些发送到我的身份验证服务的请求没有设置会话 cookie,对于某些路径甚至不应该使用它。 所以我定义了那些与会话相关的路径:
const sessionPaths = ['/path1', '/path2', ...];
app.use(sessionPaths, session(sessionOptions));
app.use(sessionPaths, passport.initialize());
app.use(sessionPaths, passport.session());
app.use(sessionPaths, csrf());
不确定这是否已完全解决,但鉴于您的布局顺序,您可能在会话处理程序之后有 cors 处理程序。当预检请求进入时,可能会为每个请求创建一个会话,因为没有发送会话 cookie 或凭据。简单的解决方法是将 cors 处理程序移动到会话处理程序之上。