为什么刷新令牌没有作为http cookie发送到服务器?

问题描述 投票:0回答:1

当我尝试在请求中创建产品时,我的应用程序没有发送刷新令牌 cookie。

首先,当我登录时,我的refreshToken被设置为cookie,我可以在开发者工具的应用程序部分看到它。

export const login = async (req, res) => {
    try {
      const { email, password } = req.body;
      const user = await User.findOne({ email: email });
      console.log(user);
      if (!user) return res.status(400).json({ msg: "User does not exist. " });

  
      const isMatch = await bcrypt.compare(password, user.password);
      if (!isMatch) return res.status(400).json({ msg: "Invalid credentials. " });

    let accessToken, refreshToken;
    try {
      accessToken = jwt.sign(
        { userId: user._id, email: user.email },
        process.env.JWT_SECRET,
        { expiresIn: "2m" }
      );
      refreshToken = jwt.sign(
        { userId: user._id },
        process.env.REFRESH_TOKEN_SECRET,
        { expiresIn: "7d" }
      );
      const SetCookie = res.cookie("refreshToken", refreshToken, {
      httpOnly: true,
      expires: new Date(Date.now() + 7 * 24 * 60 * 60 * 1000), // 7 days
    })
    console.log(SetCookie)
    } catch (err) {
      console.error(err);
      res
        .status(500)
        .json({ message: "Signing up failed, please try again later." });    
    }
      res.status(200).json({  message: "logged in!", user, accessToken, refreshToken });
    } catch (err) {
      console.error(err);
      res.status(500).json({ error: err.message });
    }
}

然后,我等待 jwt 令牌过期,以测试我的刷新令牌在创建产品时是否有效。 这是设置配置的 asyncThunk,withCredentials:true 允许 axios 向我的服务器发送 cookie。

export const addProduct = createAsyncThunk(
  'product/addProduct',
  async (productData, { rejectWithValue }) => {
    try {
      const { user, token, formData } = productData;
      const url = `http://localhost:3005/product/${user._id}/add-product`;

      const config = {
        headers: {
          Authorization: `Bearer ${token}`,
          'Content-Type': 'multipart/form-data',
        },
        withCredentials: true,
      };

      const response = await axios.post(url, formData, config,);
      console.log(response);
      const newProduct = response.data.product;

      return newProduct;
    } catch (error) {
      console.error(error);
      console.error(error?.response?.data ?? error.message);

      return rejectWithValue(error.response.data);
    }
  }
);

但是发生错误并表示身份验证失败,因为 jwt 令牌已过期。此错误来自处理受保护路由的身份验证的 checkAuth 函数。问题是,当我尝试在 if 语句之外进行控制台记录时, req.cookies.refreshToken 未定义。这意味着 cookie 不会发送到后端。 这是检查验证码:

export const checkAuth = async (req, res, next) => {
  try {
    const authHeader = req.headers.authorization;
    if (!authHeader) {
      throw new Error("Authentication failed!");
    }

    const token = authHeader.split(" ")[1]; // Authorization: Bearer <token>

    const decodedToken = jwt.verify(token, process.env.JWT_SECRET);
    req.userData = { userId: decodedToken.userId };

    console.log(`DecodedToken Time : ${decodedToken.exp}`) 
    console.log(`Start, ${token}, end`)   

    const currentTime = Date.now() / 1000; // convert to seconds
    // const currentTime = Math.floor(Date.now() / 1000); // convert to seconds
    if (decodedToken.exp - currentTime < 60) {
      const rToke = req.headers.cookie
      const refreshToken = rToke.split('=')[1];
      console.log(`refreshToken:${refreshToken}`)
      // Access token has expired, try to refresh using refresh token
      // console.log(refreshToken)
      if (!refreshToken) {
        throw new Error("Refresh token not found!");
      }
      try {
        const decodedRefreshToken = jwt.verify(
          refreshToken,
          process.env.REFRESH_TOKEN_SECRET
        );
        console.log(decodedRefreshToken, 'refresh token was verified!')
      } catch (error) {
        console.error(error)
      }
      
      // Validate the user from the decodedRefreshToken if necessary

      // Generate a new access token and refresh token
      const newAccessToken = jwt.sign(
        { userId: decodedToken.userId },
        process.env.JWT_SECRET,
        { expiresIn: "3m" }
      );
      const newRefreshToken = jwt.sign(
        { userId: decodedToken.userId },
        process.env.REFRESH_TOKEN_SECRET,
        { expiresIn: "7d" }
      );
      res.cookie("refreshToken", newRefreshToken, { httpOnly: true });

      // Send the new access token in the response headers
      console.log(newAccessToken)
      res.set("Authorization", `Bearer ${newAccessToken}`);
      // res.json({newAccessToken})
    } else {
      const decodedToken = jwt.verify(token, process.env.JWT_SECRET);

    }

    next();
  } catch (err) {
    const error = new HttpError('Authentication failed', 401);
    return next(error);
  }
};

更令人困惑的是,我已将服务器配置为接受 cookie 以及跨源请求。 这是来自服务器的 index.js 的代码:

app.use(cors({
  origin: 'http://localhost:3000',
  credentials: true,
  cookie: {
    domain: 'localhost',
  },
}));

app.use((req, res, next) => {
  res.setHeader('Access-Control-Allow-Origin', 'http://localhost:3000');
  res.setHeader('Access-Control-Allow-Credentials', true);
  res.setHeader(
    'Access-Control-Allow-Headers',
    'Origin, X-Requested-With, Content-Type, Accept, Authorization'
  );
  res.setHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, OPTIONS, DELETE');

  next();
});

app.use(cookieParser());

那么为什么刷新令牌不作为 cookie 发送到我的后端呢? cookie 的路径设置为“/”,域设置为“localhost”。任何帮助将非常感激。谢谢。

reactjs express jwt mern refresh-token
1个回答
0
投票

据我所知,刷新令牌仅适用于 https cookie。 尝试将其更改为https协议。它确实有效。

© www.soinside.com 2019 - 2024. All rights reserved.