req.user jwt 刷新后丢失数据
req.user losing data after jwt refresh
首先让我提供所有相关代码然后我将解释我的问题
我用于验证 jwt 的中间件
module.exports.authenticateToken = (req, res, next) => {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (!token) {
return res.status(401).json({ success: false, msg: "not authorized" });
}
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) {
return res
.status(403)
.json({ success: false, msg: "jwt cannot be verified" });
}
req.user = user;
next();
});
};
我生成访问和刷新令牌的代码
module.exports.generateAccessToken = (user) => {
const payload = {
sub: user._id,
name: user.username,
};
return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "20s",
});
};
module.exports.generateRefreshToken = (user) => {
const payload = {
sub: user._id,
name: user.username,
};
return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET);
}
这是用户登录时发生的情况(我将刷新令牌存储在一个数组中 rn 当我让所有这些都正常工作时我会更改它)
module.exports.postAuthLogin = async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({ success: false, msg: "Invalid username" });
}
const passwordIsValid = validatePasswordHash(
password,
user.salt,
user.hash
);
if (!passwordIsValid) {
return res.status(401).json({ success: false, msg: "Invalid password" });
}
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
refreshTokens.push(refreshToken);
res.status(200).json({ success: true, accessToken, refreshToken });
} catch (err) {
return res.json({ msg: err.toString() });
}
};
最后,这是当用户请求刷新令牌时运行的程序
module.exports.postAuthRefreshToken = (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) {
return res
.status(401)
.json({ success: false, msg: "must provide a refresh token" });
}
if (!refreshTokens.includes(refreshToken)) {
return res.status(403).json({
success: false,
msg: "refresh token was deleted you must login again",
});
}
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
const accessToken = generateAccessToken(user);
res.status(200).json({ success: true, accessToken });
});
};
所以我的问题最初是当我登录并获取我的刷新和访问令牌时,然后我请求一个受 authenticateToken 中间件保护的路由我的 req.user 在该路由中看起来像这样
{
sub: '5ff5f16f4203ade4d1b63da8',
name: 'test1',
iat: 1610055109,
exp: 1610055129
}
但是当我的令牌过期并且我请求一个新令牌时它确实得到验证并且我能够访问受保护的路由但是我的req.user看起来像这样
{ iat: 1610055143, exp: 1610055163 }
我已经为这个问题苦苦思索了一段时间,所以任何帮助都将不胜感激,如果您需要更多信息,请说些什么,我会 100% 提供
问题就在这里
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
const accessToken = generateAccessToken(user);
res.status(200).json({ success: true, accessToken });
});
“用户”实际上将成为解码后的有效载荷
{
sub: '5ff5f16f4203ade4d1b63da8',
name: 'test1',
iat: 1610055109,
exp: 1610055129
}
然后将其传递给 generateAccessToken 并尝试访问未定义的字段 _id 和用户名。
您可以将负载字段更改为
{
_id: '5ff5f16f4203ade4d1b63da8',
username: 'test1',
iat: 1610055109,
exp: 1610055129
}
因此,当传递解码后的有效负载时,它仍将具有相同的字段名称。
或者您可以使用 payload.sub 再次从数据库中获取用户,然后将用户传递给 generateAccessToken。
首先让我提供所有相关代码然后我将解释我的问题
我用于验证 jwt 的中间件
module.exports.authenticateToken = (req, res, next) => {
const authHeader = req.headers["authorization"];
const token = authHeader && authHeader.split(" ")[1];
if (!token) {
return res.status(401).json({ success: false, msg: "not authorized" });
}
jwt.verify(token, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) {
return res
.status(403)
.json({ success: false, msg: "jwt cannot be verified" });
}
req.user = user;
next();
});
};
我生成访问和刷新令牌的代码
module.exports.generateAccessToken = (user) => {
const payload = {
sub: user._id,
name: user.username,
};
return jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
expiresIn: "20s",
});
};
module.exports.generateRefreshToken = (user) => {
const payload = {
sub: user._id,
name: user.username,
};
return jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET);
}
这是用户登录时发生的情况(我将刷新令牌存储在一个数组中 rn 当我让所有这些都正常工作时我会更改它)
module.exports.postAuthLogin = async (req, res) => {
const { username, password } = req.body;
try {
const user = await User.findOne({ username });
if (!user) {
return res.status(401).json({ success: false, msg: "Invalid username" });
}
const passwordIsValid = validatePasswordHash(
password,
user.salt,
user.hash
);
if (!passwordIsValid) {
return res.status(401).json({ success: false, msg: "Invalid password" });
}
const accessToken = generateAccessToken(user);
const refreshToken = generateRefreshToken(user);
refreshTokens.push(refreshToken);
res.status(200).json({ success: true, accessToken, refreshToken });
} catch (err) {
return res.json({ msg: err.toString() });
}
};
最后,这是当用户请求刷新令牌时运行的程序
module.exports.postAuthRefreshToken = (req, res) => {
const { refreshToken } = req.body;
if (!refreshToken) {
return res
.status(401)
.json({ success: false, msg: "must provide a refresh token" });
}
if (!refreshTokens.includes(refreshToken)) {
return res.status(403).json({
success: false,
msg: "refresh token was deleted you must login again",
});
}
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
const accessToken = generateAccessToken(user);
res.status(200).json({ success: true, accessToken });
});
};
所以我的问题最初是当我登录并获取我的刷新和访问令牌时,然后我请求一个受 authenticateToken 中间件保护的路由我的 req.user 在该路由中看起来像这样
{
sub: '5ff5f16f4203ade4d1b63da8',
name: 'test1',
iat: 1610055109,
exp: 1610055129
}
但是当我的令牌过期并且我请求一个新令牌时它确实得到验证并且我能够访问受保护的路由但是我的req.user看起来像这样
{ iat: 1610055143, exp: 1610055163 }
我已经为这个问题苦苦思索了一段时间,所以任何帮助都将不胜感激,如果您需要更多信息,请说些什么,我会 100% 提供
问题就在这里
jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET, (err, user) => {
const accessToken = generateAccessToken(user);
res.status(200).json({ success: true, accessToken });
});
“用户”实际上将成为解码后的有效载荷
{
sub: '5ff5f16f4203ade4d1b63da8',
name: 'test1',
iat: 1610055109,
exp: 1610055129
}
然后将其传递给 generateAccessToken 并尝试访问未定义的字段 _id 和用户名。
您可以将负载字段更改为
{
_id: '5ff5f16f4203ade4d1b63da8',
username: 'test1',
iat: 1610055109,
exp: 1610055129
}
因此,当传递解码后的有效负载时,它仍将具有相同的字段名称。 或者您可以使用 payload.sub 再次从数据库中获取用户,然后将用户传递给 generateAccessToken。