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

本地环境Cookie无法获取求助:登录接口设置Cookie不生效

问题:浏览器无法显示登录后设置的Token Cookie,导致用户验证失败

我正在搭建应用的用户验证系统,但无法从浏览器Cookie中获取token完成验证,核心问题是Cookie并未在浏览器中显示。

登录控制器代码(应用仅含登录控制器,无注册控制器)

import { getConnection } from '../database/connection.js';
import createAccessToken from '../libs/jwt.js';
import { queriesUsers } from '../database/queries.js';
import { serialize } from 'cookie';

export const loginController = async (req, res) => {
    try {
        const { username, password } = req.body; 

        const pool = await getConnection(); 
        const result = await pool
            .request()
            .input("username", username) 
            .input("password", password) 
            .query(queriesUsers.validateUser);
  
        const user = result.recordset[0]; 

      if (user && user.Type === 'S') {
        const token = createAccessToken(user);
        if (token) {
          console.log(token)
          res.cookie("Token", token, {
            httpOnly: true,
            maxAge: 600000,
          });
          console.log("cookies", req.cookies);
          res.status(200).json({token});
        } else {
          res.status(500).json({ error: "Error"});
        }
      } else {
        res.status(401).json({ error: 'Credenciales inválidas' });
      }
  
    } catch (error) {
      console.error("Error al validar el usuario:", error);
      res.status(500).json({ error: "Error al validar el usuario" });
    }
  };

控制台打印结果

当我打印req.cookies时,输出为:

cookies [Object: null prototype] {}

前端Login组件代码

import React, { useState, useContext } from 'react';
import styles from '../styles/login.module.css';
import { useNavigate } from 'react-router-dom';
import { AuthContext } from '../context/AuthContext'; 

const Login = () => {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');

  const navigate = useNavigate();
  const { login } = useContext(AuthContext); 

  const handleUsernameChange = (event) => {
    setUsername(event.target.value);
  };

  const handlePasswordChange = (event) => {
    setPassword(event.target.value);
  };

  const handleSubmit = async (event) => {
    event.preventDefault();

    try {
      await login(username, password);
    } catch (error) {
      if (error.response) {
        setError('Error al iniciar sesión. Verifica tus credenciales.');
      } else {
        setError('Error de conexión. Inténtalo nuevamente más tarde.');
      }
    }

    setPassword('');
    setUsername('');
  };

  return (
    <div className={styles.main}>
        <div className={styles.descriptionContainer}>
          <img className={styles.logo} src="/biconlogo - copia.png" alt="bicon" />
          <h2 className={styles.subtitle}>¡Bienvenido!</h2>
          <p className={`${styles.descriptionText} ${styles.paragraph}`}>
            <b>BiCon Survey</b> es una solución que permite a los colaboradores
            identificar las actividades que se realizan y asignarles un peso que
            refleje la intensidad con la que ejecutan. La información recabada
            será de utilidad para el Modelo de Costeo Basado en Actividades.
          </p>
        </div>

        <div className={styles.login}>
          <h2 className={styles.loginH2}>Iniciar sesión</h2>
          {error && <p className={styles.error}>{error}</p>}
          <form className={styles.loginForm} onSubmit={handleSubmit}>
            <div>
              <label className={styles.loginLabel} htmlFor="username">
                Usuario:
              </label>  
              <input
                className={styles.loginInput}
                value={username}
                onChange={handleUsernameChange}
              />
            </div>

            <div>
              <label className={styles.loginLabel} htmlFor="password">
                Contraseña:
              </label>
              <input
                type="password"
                className={styles.loginInput}
                value={password}
                onChange={handlePasswordChange}
              />
            </div>

            <button type="submit" className={styles.loginButton}>
              Iniciar sesión
            </button>
          </form>
        </div>
      </div>
  )
}

export default Login;

AuthContext代码

import { createContext, useState, useContext } from "react";
import axios from 'axios';

export const AuthContext = createContext();

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error("useAuth must be within AuthProvider");
  }
  return context;
}

export const AuthProvider = ({ children }) => {
  const [user, setUser] = useState(null);
  const [token, setToken] = useState(null); 
  const [isAuthenticated, setIsAuthenticated] = useState(false);
  const [errors, setErrors] = useState([]);

  const login = async (username, password) => {
    try {
      const response = await axios.post('http://localhost:4000/api/login', {
        username: username,
        password: password,
      });

      const authToken = response.data.token;
      console.log(authToken)

      setUser({ ...response.data.user, token: authToken });
      setToken(authToken); 
      setIsAuthenticated(true);
      setErrors([]);
    } catch (error) {
      setErrors(error.response.data);
    }
  }

  const logout = () => {
    setUser(null); 
    setToken(null);
    setIsAuthenticated(false);
    setErrors([]);
  }

  return (
    <AuthContext.Provider value={{
      user,
      token,
      isAuthenticated,
      errors,
      login,
      logout,
    }}>
      {children}
    </AuthContext.Provider>
  )
}

解决方案

Cookie无法在浏览器显示的核心原因是跨域请求的Cookie配置缺失,以及后端和前端的几个关键设置错误,以下是分步修复方案:

1. 后端Cookie配置补全

你的res.cookie缺少几个关键参数,导致浏览器拒绝存储Cookie:

  • secure: 生产环境必须设为true(仅通过HTTPS传输),开发环境可暂时设为false
  • sameSite: 根据跨域情况设置,开发环境建议设为"Lax",生产环境跨域时设为"None"(需配合secure: true)
  • path: 明确Cookie生效路径,一般设为"/"

修改后的res.cookie代码:

res.cookie("Token", token, {
  httpOnly: true,
  maxAge: 600000,
  secure: process.env.NODE_ENV === "production",
  sameSite: process.env.NODE_ENV === "production" ? "None" : "Lax",
  path: "/"
});

另外,登录接口中打印req.cookies无效——当前请求是登录请求,Cookie还未被浏览器存储,无法从req.cookies获取刚设置的Token,该打印只能看到浏览器发送过来的Cookie。

2. 后端开启CORS跨域支持

若前端与后端跨域(如前端localhost:3000、后端localhost:4000),需在后端配置CORS允许携带Cookie。以Express为例,安装cors包后配置:

const cors = require('cors');
app.use(cors({
  origin: "http://localhost:3000", // 你的前端地址
  credentials: true // 允许携带Cookie
}));

3. 前端Axios配置修改

前端Axios请求未开启withCredentials,导致浏览器不会接收并存储后端设置的Cookie。修改AuthContext中的请求:

const response = await axios.post('http://localhost:4000/api/login', {
  username: username,
  password: password,
}, {
  withCredentials: true // 关键:允许携带Cookie
});

4. 验证流程调整

当前你将Token同时存在Cookie和Context中,建议优化:

  • 后端设置httpOnly的Cookie后,前端无需手动存储Token到Context,后续请求会自动携带Cookie
  • 验证接口直接从req.cookies.Token中获取Token校验,无需前端传递

按以上步骤修改后,浏览器即可正常显示并存储Token Cookie,验证流程可正常运行。


内容的提问来源于stack exchange,提问作者José andres Guzman

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 03:35:37