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

基于Cookie认证的MERN预订项目部署后Cookie无法设置求助

MERN项目Cookie认证失败排查求助

已部署基于Cookie认证的MERN预订项目,接口能正常返回用户信息,但Cookie始终无法在客户端设置。已配置SameSite: none、Secure: true,服务端开启credentials,客户端请求也设置了withCredentials: true,但Cookie仍不存在。以下是相关代码,寻求解决办法:

客户端地址:https://waneem-admin.onrender.com


服务端代码

index.js

import express from 'express'
import dotenv from "dotenv"
import hotelRouter from './routers/hotel.route.js'
import userRouter from './routers/user.route.js'
import authRouter from './routers/auth.route.js'
import roomRouter from './routers/rooms.route.js'
import bookingrouter from './routers/booking.route.js'

import cookieParser from 'cookie-parser'
import cors from 'cors'
import ErrorHandler from './utils/ErrorHandler.js'
dotenv.config()

export const app = express();
app.use(cookieParser())

//middleware
app.use(cors({
    origin: "https://waneem-admin.onrender.com",
    credentials: true,
    optionSuccessStatus: true,
    methods: "*"
}))
app.set("trust proxy", 1)

app.use(express.json())
//router
app.use('/api/v1/auth', authRouter)
app.use('/api/v1/hotels', hotelRouter)
app.use('/api/v1/room', roomRouter)
app.use('/api/v1/booking', bookingrouter)

app.use('/api/v1/user', userRouter)

const toke = "Sdfsdfsd"
app.get(
    '/api/v1', (req, res) => {
        console.log(toke)
        console.log('here')
        res.status(200).cookie("access_token", toke, {
            httpOnly: true,
            maxAge: 24 * 60 * 60 * 1000,
            sameSite: "none",
            secure: true
        }).send('hello from express')
        console.log(res)
    }
)
console.log(process.env.ADMIN_URL, process.env.CLIENT_URL)

//error middleware
app.use(ErrorHandler)

server.js

import { app } from './index.js'
import connectDB from './database.js'

app.listen(process.env.SERVER_PORT, () => {
    connectDB()
    console.log("listening on port 3000")
})

Auth控制器(register方法)

import User from "../models/user.model.js"
import CreateError from "../utils/CreateError.js"
import bcrypt from "bcrypt"
import jwt from "jsonwebtoken"
import { Sendtoken } from "../utils/Sendtoken.js"

export const register = async (req, res, next) => {
    try {
        const { password, isAdmin, ...data } = req.body;
        let isadmin = false;

        // Verify the token
        const token = req.cookies.access_token;

        if (token) {
            const decoded = jwt.verify(token, process.env.JWT_SECRET);
            if (decoded && decoded.isAdmin) {
                isadmin = req.body.isAdmin || false;
            }
        }

        // Check if a user with the same email already exists
        const existingUser = await User.findOne({ email: data.email });
        if (existingUser) {
            return next(CreateError(400, `User with email ${data.email} already exists`));
        }

        // Hash the password
        const hashedPassword = await bcrypt.hash(password, 12);

        // Create a new user
        const user = new User({
            ...data,
            password: hashedPassword,
            isAdmin: isadmin,
        });

        // Save the user
        await user.save();

        // Generate and send the token
        Sendtoken(user, res, 200, "User registered successfully", next);
    } catch (err) {
        return next(err);
    }
};

Sendtoken工具函数

import CreateError from "./CreateError.js";
import jwt from "jsonwebtoken"

export const Sendtoken = async (user, res, statusCode = 200, message, next) => {
    try {
        const token = await jwt.sign({ id: user._id, isAdmin: user.isAdmin }, process.env.JWT_SECRET, { expiresIn: "1d" })

        return res.status(statusCode).cookie("access_token", token, {
            httpOnly: true,
            maxAge: 24 * 60 * 60 * 1000,
            sameSite: "none",
            secure: true
        }).json({
            success: true,
            message: message || 'login successfull',
            user: user
        })
    } catch (err) {
        console.log(err)
        return next(err)
    }
}

客户端Login组件代码

import React, { useContext, useState } from "react"
import { Authcontext } from "../../context/Authcontext.jsx"
import axios from "axios"
import "./Login.scss"
import { useNavigate } from "react-router-dom"
const Login = () => {

  const [credentials, setCredentials] = useState({
    email: undefined,
    password: undefined,
  })
  const { currentUser, loading, error, dispatch } = useContext(Authcontext)
  const handlechange = (e) => {
    console.log(e.target.value)
    return setCredentials((prev) => ({
      ...prev,
      [e.target.id]: e.target.value,
    }))
  }

  console.log(loading)
  const navigate = useNavigate()
  const handlesubmit = async (e) => {
    e.preventDefault()
    console.log("handlesubmit")
    console.log("here")

    dispatch({ type: "START" })
    try {
      const { email, password } = credentials
      const res = await axios.post(`${import.meta.env.VITE_REACT_SERVER_URL}/api/v1/auth/login`, {
        email: email,
        password: password,
      },
        {
          withCredentials: true,
          headers: {
            "Content-Type": "application/json",
          },
        })
      dispatch({ type: "SUCCESS", payload: res?.data?.user })
      navigate('/')
    } catch (err) {
      console.log(err, "by here this error")
      dispatch({ type: "FAILURE", payload: err.response.data.message })
    }
  }

  return (
    <form className="login" onSubmit={handlesubmit} autoComplete="new-password">
      <div className="loginwrapper">
        <h1> Login</h1>
        <input
          className="logininput"
          placeholder="username"
          type="email"
          id="email"
          value={credentials.email}
          onChange={handlechange}
        />
        <input
          className="logininput"
          placeholder="password"
          type="password"
          autoComplete="new-password"
          id="password"
          value={credentials.password}
          onChange={handlechange}
        />
        <button disabled={loading} className="btn" type="submit">
          submit
        </button>
        {error && <span className="error"> {error}</span>}
        <div className="form-bottom">
          <span className="forgot">Forgot Password?</span>
          <span className=" registerbtn" onClick={() => navigate('/register')}>Register here</span></div>
      </div>
    </form>
  )
}

export default Login

排查建议

  1. 检查域名匹配:确认服务端CORS配置的origin与客户端实际域名完全一致,包括协议、域名、端口(如有),避免多余斜杠或拼写错误。
  2. 查看响应头:在浏览器Network面板中检查登录/注册接口的响应头,确认Set-Cookie字段是否存在,且属性(SameSite、Secure、HttpOnly)配置正确。若字段缺失,说明服务端未正确输出Cookie。
  3. 调整代理信任:服务端已设置trust proxy:1,可尝试改为trust proxy: true,适配Render的代理环境。
  4. 添加Cookie域名:在Cookie配置中增加domain属性,值为服务端主域名(如.your-server-domain.com),适配跨域场景的Cookie存储规则。
  5. 检查浏览器隐私设置:关闭浏览器"阻止第三方Cookie"选项,跨域场景下该设置会阻止Cookie存储。
  6. 测试基础接口:先调用服务端/api/v1GET接口,验证是否能设置Cookie,排除登录/注册逻辑中的问题。
  7. 全局Axios配置:确保客户端Axios全局开启withCredentials: true,避免个别请求遗漏配置。

内容的提问来源于stack exchange,提问作者wakai-megumi

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 02:40:35