You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

部署后Node.js无法在Vercel前端设置JWT Cookie问题求助

跨域部署后JWT Token无法在浏览器保存为Cookie的问题

后端部署至Azure、前端部署至Vercel后,登录成功后Token已返回但无法在浏览器保存为Cookie。本地环境功能正常,线上完全失效;Postman中可正常保存Cookie,但浏览器环境不生效。测试账号:user,密码:user。

相关代码

登录路由代码

router.post("/login", async (req, res, next) => {
  try {
    const { username, password } = req.body;
    const user = await User.findOne({
      where: {
        userName: username,
      },
    });

    if (user) {
      const match = await bcrypt.compare(
        password,
        user.getDataValue("passWord")
      );
      if (match) {
        const token = createToken(user.id);
        res.cookie("jwt", token, {
          httpOnly: false,
          maxAge: maxAge * 1000,
          sameSite: "lax",
          secure: true,
        });
        res.status(200).json({ user });
      } else {
        res.status(400).json({ message: "Invalid username or password" });
      }
    } else {
      res.status(400).json({ message: "Invalid username or password" });
    }
  } catch (error) {
    next(error); // Pass any errors to the error handling middleware
  }
});

Token验证路由代码

router.get("/profile", verifyToken, async (req, res) => {
  try {
    // Access user information from req.user
    const user: any = req.user;

    // Check if user is null or undefined
    if (!User) {
      return res.status(404).json({ message: "User not found" });
    }

    const { id } = user;

    const userOne = await User.findOne({
      where: {
        id: id,
      },
    });
    // You can now use the user information as needed
    res.json(userOne);
  } catch (error) {
    res.status(500).json({ message: "Internal server error" });
  }
});

前端(Vite)登录代码

const handleLogin = async (e: any) => {
    e.preventDefault();
    try {
      const response = await fetch(
        "https://workdbackend.azurewebsites.net/auth/login",
        {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          credentials: "include",
          body: JSON.stringify({ username, password }),
        }
      );

      if (response.ok) {
        const data = await response.json();
        console.log(data);
        dispatch(login(data));
      } else {
        // Login failed
        setError("שם משתמש או סיסמה לא נכונים");
      }
    } catch (error) {
      console.error("Login error:", error);
    }
  };

已尝试的调整

  • CORS配置修改:
const corsOptions = {
allowedHeaders: [
"Origin",
"X-Requested-With",
"Content-Type",
"Accept",
"X-Access-Token",
"Authorization",
],
methods: "GET,HEAD,PUT,PATCH,POST,DELETE",
origin: "https://claim-work.vercel.app",
credentials: true,
preflightContinue: false,
};
  • Cookie参数修改:
res.cookie("jwt", token, {
httpOnly: false,
maxAge: maxAge * 1000,
sameSite: "none",
secure: true,
});

问题分析与解决方案

核心原因

跨域场景下,浏览器对Cookie的保存有严格安全限制,需同时满足多个条件才能正常存储。

具体修复步骤

  1. 确认Azure后端HTTPS配置
    确保Azure服务已启用HTTPS,secure: true要求Cookie仅通过HTTPS传输,若后端为HTTP,浏览器会拒绝保存。

  2. 修正Cookie配置
    跨域场景下必须设置sameSite: "none",同时建议开启httpOnly: true提升安全性(前端无需手动读取Cookie,请求会自动携带):

    res.cookie("jwt", token, {
      httpOnly: true,
      maxAge: maxAge * 1000,
      sameSite: "none",
      secure: true,
    });
    
  3. 完善CORS配置

    • 确保origin设置准确,若有多个前端域名,建议用动态函数验证而非固定值;
    • 确认响应头包含Access-Control-Allow-Credentials: true,这是浏览器允许携带Cookie的必要条件;
    • 检查预检请求(OPTIONS)是否被正确处理,preflightContinue: false确保中间件直接响应预检请求。
  4. 前端请求检查

    • 所有需要携带Cookie的请求(如/profile)都要设置credentials: "include";
    • 排查Vite项目中是否有拦截器修改了请求头或credentials配置。
  5. 浏览器控制台排查

    • 打开开发者工具Application标签,查看Cookie是否存在;
    • 查看Network标签中登录请求的响应头,确认Set-Cookie字段存在,以及浏览器是否有Cookie被阻止的警告信息。
  6. Azure服务配置检查

    • 在Azure门户的App Service中,确认CORS设置已添加前端域名并启用"允许凭据";
    • 检查是否存在强制HTTP的重定向规则,确保所有请求都走HTTPS。

内容的提问来源于stack exchange,提问作者just Props

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 12:41:07