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

使用jwt.verify验证令牌出错:Bearer null与401未授权问题

JWT验证令牌失败导致401 Unauthorized的问题修复

问题现象

登录成功后刷新页面,访问/profile接口返回401 Unauthorized状态码;查看请求头发现Authorization: "Bearer null",后端无法获取JWT令牌完成验证。

相关代码片段

后端登录接口(Node.js/Express)

app.post('/login', async (req, res) => {
  try {
    const { email, password } = req.body;

    // 检查用户是否存在
    const user = await User.findOne({ email });
    if (!user) {
      return res.json({
        error: '未找到用户',
      });
    }

    // 验证密码
    const match = await comparePasswords(password, user.password);

    if (match) {
      jwt.sign( {email: user.email, name: user.name}, process.env.JWT_SECRET, {expiresIn: 86400}, (err, token) => {
        if (err) {
          console.error("生成JWT错误:", err);
          return res.status(500).json({ error: "服务器内部错误" });
        }

        res.cookie('token', token).json({ user });
      });
    }
  } catch (err) {
    console.log(err);
  }
});

后端/profile接口

app.get('/profile', (req, res) => {
  // 从Cookie获取JWT令牌
  const { token } = req.cookies;
  jwt.verify(token, process.env.JWT_SECRET, {}, (err, user) => {
    if (err) throw err;
    res.json(user);
})
});

前端UserContext.tsx

import Axios from "axios";
import { createContext, useState, useEffect } from "react";

export const UserContext = createContext({ user: null });

interface UserContextProviderProps {
  children: JSX.Element | JSX.Element[];
}

export function UserContextProvider({ children }: UserContextProviderProps) {
  const [user, setUser] = useState(null);

  useEffect(() => {
    if (user === null) {
      Axios.get("/profile")
        .then(({ data }) => {
          setUser(data);
        })
        .catch((error) => {
          console.error("获取用户信息失败:", error);
        });
    }
  }, []);

  return (
    <UserContext.Provider value={{ user }}>{children}</UserContext.Provider>
  );
}

前端Login.tsx

const [data, setData] = useState({
    email: "",
    password: "",
  });

  const navigateTo = useNavigate();

  const handleLogin = async (ev: any) => {
    ev.preventDefault();
    const { email, password } = data;

    try {
      const { data } = await Axios.post("/login", {
        email,
        password,
        headers: {
          Authorization: "Bearer " + localStorage.getItem("token"),
          "Content-Type": "application/json",
        },
      });

      if (data.error) {
        toast.error(data.error);
      } else {
        setData({ email: "", password: "" });
        toast.success("登录成功");
        navigateTo("/");
      }
    } catch (err) {
      console.log(err);
    }
  };

问题根源分析

  1. Login.tsx多余的Authorization头:登录时localStorage.getItem("token")返回null,导致请求头出现无效的Authorization: "Bearer null",且登录接口根本不需要该头。
  2. Axios未配置跨域携带Cookie:后端将token存在Cookie中,但前端Axios默认不会携带Cookie(跨域场景下更明显),导致/profile接口无法从req.cookies获取到token。
  3. 后端/profile接口错误处理不当:token不存在或验证失败时直接throw err,会导致服务器崩溃,无法正确返回401响应。
  4. Cookie属性配置缺失:后端设置Cookie时未指定httpOnly、sameSite等属性,可能导致浏览器无法正确存储或携带Cookie。

修复方案

1. 修复Login.tsx

移除登录请求中不必要的Authorization头:

const handleLogin = async (ev: any) => {
  ev.preventDefault();
  const { email, password } = data;

  try {
    const { data } = await Axios.post("/login", {
      email,
      password,
      headers: {
        "Content-Type": "application/json",
      },
    });

    if (data.error) {
      toast.error(data.error);
    } else {
      setData({ email: "", password: "" });
      toast.success("登录成功");
      navigateTo("/");
    }
  } catch (err) {
    console.log(err);
  }
};

2. 配置Axios携带Cookie

在项目入口文件或UserContext中全局配置Axios的withCredentials:

// 全局配置,确保所有请求携带Cookie
Axios.defaults.withCredentials = true;

或单独在/profile请求中设置:

Axios.get("/profile", { withCredentials: true })
  .then(({ data }) => {
    setUser(data);
  })
  .catch((error) => {
    console.error("获取用户信息失败:", error);
  });

3. 修复后端/profile接口错误处理

替换throw err为返回401响应,避免服务器崩溃:

app.get('/profile', (req, res) => {
  const { token } = req.cookies;
  if (!token) {
    return res.status(401).json({ error: '未提供令牌' });
  }
  jwt.verify(token, process.env.JWT_SECRET, {}, (err, user) => {
    if (err) {
      return res.status(401).json({ error: '令牌无效或已过期' });
    }
    res.json(user);
  })
});

4. 优化后端Cookie配置

添加安全属性,确保浏览器正确处理Cookie:

// 登录接口中设置Cookie时补充属性
res.cookie('token', token, {
  httpOnly: true, // 防止XSS攻击,前端无法通过JS访问Cookie
  secure: process.env.NODE_ENV === 'production', // 生产环境仅通过HTTPS传输
  sameSite: 'strict', // 防范CSRF攻击
  maxAge: 86400 * 1000 // 过期时间与JWT保持一致
}).json({ user });

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.09 05:34:54