我正在开发一个api与express.js和认证系统,我使用从jwt库和刷新和访问令牌。一切工作时,我测试我的代码与jest和supertest和测试它与 Postman 。
在前端,我使用react,并将刷新令牌保存在cookie(仅httpOnly)中,使用redux将用户数据(如访问令牌、刷新令牌和用户名)保存在内存中,一切正常(路由保护等)。
当用户离开程序时,存储器被清除(保存在redux中的用户信息将被删除),当程序的用户返回登录页面时,这是正常的。
但是我在cookie中有刷新令牌,并且我用withCredentials=true
的axios方法向**/tokens**API发送post请求,用于生成新的访问和刷新令牌,一切正常,并返回新令牌和用户数据,并且用户没有重定向到验证页面。
- 问题是**
我使用react版本18.2.0,并且我知道当在开发模式下的useEffect中调用两次useEffect时,没有问题。我向/tokens
api发送post请求,以在useEffect中生成新的访问和刷新令牌。根据前面的语句,在开发模式下发送了两次此请求。
我在api中的逻辑,使用与cookie一起发送的刷新令牌搜索用户,如果找到用户,则生成新令牌。
- 但我注意到在两次调用中,第一次api调用(/tokens)找到用户,但第二次调用无法找到用户并返回未定义**,有时两次调用都成功,这很奇怪。
- 这是我的密码**
React代码:
useEffect(() => {
if (user === undefined) {
axios.post('/tokens').then((result: any) => {
dispatch(addUser(result.data.user));
}).catch((error: any) => {
dispatch(addUser(undefined))
})
}
}, []);
后端代码:
tokens = async (req: Request, res: Response, next: NextFunction): Promise<Response> => {
const refreshToken = req.headers.cookie?.split('=')[1];
const user: any[] = await this._userRepository.find({
fields: [
{
field: {
username: req.user.username,
email: req.user.email,
id: req.user.id,
refresh_token: refreshToken
},
op: 'AND'
}
]
});
// in here sometimes find user and sometimes cannot find user with same data
if (user[0] !== undefined) {
const newAccessToken: string = generateJwt('access_token', user[0], '1m');
const newRefreshToken: string = generateJwt('refresh_token', user[0], '10d');
await this._userRepository.update({
refresh_token: newRefreshToken,
}, {
fields: [
{
field: {
id: req.user.id,
username: req.user.username,
email: req.user.email,
refresh_token: refreshToken
},
op: 'AND'
}
]
});
const data: Record<string, any> = {
status: true,
message: 'New tokens generated successfully',
user: {
access_token: newAccessToken,
refresh_token: newRefreshToken,
}
}
return res.json(data)
}
// send error
throw new BaseError('Unauthorized', 401);
}
2条答案
按热度按时间wh6knrhe1#
这将发生在react的开发模式下。当一个组件最初呈现时,useEffect运行两次。当您在生产模式下提供react构建时,不会出现此问题。有一个解决方案可以停止两次调用useEffect,您必须从根文件中删除
React.Strict
,但不推荐使用此方法。s4n0splo2#
如果我们将前面的代码作为基础,我会看到
useEffect
为它提供了匿名函数,但我注意到它每次都会执行,也许这个函数只执行一次是个好主意,这是通过为第二个参数为useEffect
函数的数组提供一个或多个变量来实现的,我可以理解,只要user
变量被修改,您就希望它被执行,所以如果它被修改并且仍然未定义,则继续通过axios进行调用,如果没有,则什么也不做。