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

JWT实现时authorization header返回undefined及token未存储问题求助

问题排查与修复方案

核心问题点

  • 登录接口响应逻辑冲突:res.json()和res.redirect()不能同时调用,Express中单次请求仅能返回一次响应,调用res.json()后响应已结束,后续跳转逻辑不生效,前端也不会自动存储返回的token。
  • JWT签名参数错误:jwt.sign(${user}, process.env.ACCESS_TOKEN)中将user对象强制转为字符串,得到的是[object Object],签名的payload完全无效,后续校验也无法拿到正确的用户信息。
  • 无token存储逻辑:JWT需要前端主动存储(localStorage/sessionStorage/cookie),当前既没有前端存储token的逻辑,也没有服务端写cookie存储token的逻辑,后续请求自然不会携带Authorization头。
  • 鉴权中间件逻辑缺失:当前中间件仅提取token,没有做签名校验、过期校验,也没有处理Authorization头格式错误的边界情况,鉴权逻辑完全不生效。

修复方案

1. 修复登录接口逻辑

根据项目类型二选一即可:

前后端分离模式(推荐)

删除冗余的res.redirect,只返回token,跳转和存储逻辑交给前端处理:

router.post('/index', async (req, res) => {
  let post = { 
    username: req.body.username,
    password: req.body.password,
  }
  try {
    const user = await dbb('users').first('*').where({username: post.username}); 
    if(!user || !await bcrypt.compare(post.password, user.password)) {
      return res.render(path.resolve('./myviews/index'), { 
        info: 'The Username Or Password You Have Entered Does Not Match Our Records'
      });
    }
    // 修正jwt签名参数,添加过期时间
    const token = jwt.sign(
      { userId: user.id, username: user.username }, 
      process.env.ACCESS_TOKEN,
      { expiresIn: '2h' } // 可自行调整有效期
    );
    res.json({token: token});
  } catch(e) {
    console.log(e);
    res.sendStatus(500);
  }
});

服务端渲染模式

将token存入cookie后再跳转,后续请求浏览器会自动携带cookie:

// 前面逻辑和上面一致,把res.json替换成以下代码即可
res.cookie('access_token', token, { httpOnly: true, maxAge: 2 * 60 * 60 * 1000 });
res.redirect('/home');

2. 修复鉴权中间件

补充校验逻辑和边界处理:

const jwt = require('jsonwebtoken');
function authToken(req, res, next) {
  // 如果用cookie存储token,改成 const token = req.cookies.access_token; 即可
  const authHeader = req.headers['authorization'];
  if(typeof authHeader === 'undefined') return res.sendStatus(401);
  
  const bearer = authHeader.split(' ');
  if(bearer.length < 2) return res.sendStatus(401);
  const bearerToken = bearer[1];

  try {
    const decodedUser = jwt.verify(bearerToken, process.env.ACCESS_TOKEN);
    req.user = decodedUser;
    next();
  } catch (err) {
    // token过期、篡改都返回403
    return res.sendStatus(403);
  }
}

3. 补充前端逻辑(仅前后端分离模式需要)

前端收到token后主动存储,后续请求携带Authorization头:

// 登录请求处理
async function login(username, password) {
  const res = await fetch('/index', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ username, password })
  });
  const data = await res.json();
  if(data.token) {
    // 存储token
    localStorage.setItem('access_token', data.token);
    // 跳转首页
    location.href = '/home';
  }
}

// 后续鉴权请求示例,所有需要鉴权的接口都用这个方法调用即可
async function fetchAuthApi(url, options = {}) {
  const token = localStorage.getItem('access_token');
  return fetch(url, {
    ...options,
    headers: {
      ...options.headers,
      'Authorization': `Bearer ${token}`
    }
  })
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.07 08:36:01