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

Node.js学习JWT遇阻:如何在Header传递JWT并存储到浏览器localStorage

嘿,我帮你理清楚这个问题,你现在卡在JWT的前端存储和请求头传递环节,而且代码里还有几个小bug得先搞定,一步步来:

第一步:先修正代码里的致命Bug

你的routes/index.js里的登录函数有两个明显问题,导致Token根本没法正常返回给前端:

  1. 你写了response.json(...),但变量名应该是res,这会直接报错;
  2. 你先执行了res.render('home'),这已经向客户端发送了响应,后面的res.json()完全不会执行,前端根本拿不到Token。

修正后的routes/index.js:

var jwt = require('jsonwebtoken');
exports.home = function(req, res){ res.render('home',{error: false}); };
exports.loginUser = function(req, res) {
  var uname = req.body.Username;
  var pwd = req.body.Password;
  // 建议这里也给用户名加个判断,比如限定为admin,避免空用户名通过
  if(uname === 'admin' && pwd === 'admin'){
    var token = jwt.sign({ user: uname }, 'qwertyuiopasdfghj');
    console.log('Authentication is done successfully.....');
    console.log(token);
    // 登录成功后返回Token给前端,让前端自己处理跳转
    res.json({ authsuccess: true, description: 'Sending the Access Token', token: token });
  } else {
    // 处理登录失败的情况
    res.json({ authsuccess: false, description: 'Invalid username or password' });
  }
};

然后是index.js里的/home GET路由,你之前没正确从请求头取Token,而且验证成功后没返回内容,修正后:

app.get('/home',function(req, res) {
  // 从请求头获取Authorization字段,JWT标准格式是「Bearer <token>」
  const authHeader = req.headers['authorization'];
  // 拆分出Token部分(如果authHeader存在的话)
  const token = authHeader && authHeader.split(' ')[1];
  
  if (!token) {
    // 没有Token直接返回401未授权
    return res.sendStatus(401);
  }

  jwt.verify(token, 'qwertyuiopasdfghj', function(err, data) {
    if (err) { 
      res.sendStatus(403); // Token无效或过期,返回禁止访问
    } else {
      // 验证成功,渲染主页并传递用户信息
      res.render('home', { user: data.user });
    }
  });
});
第二步:前端处理Token存储和请求头携带

你的登录页面(index.ejs)需要写JS代码,处理登录请求,把返回的Token存入localStorage,然后跳转主页;后续请求时再从localStorage取出Token,放到请求头里。

登录页面(index.ejs)的代码示例:

<!DOCTYPE html>
<html>
<head>
  <title>Login</title>
</head>
<body>
  <form id="loginForm">
    <input type="text" name="Username" placeholder="Username" required>
    <input type="password" name="Password" placeholder="Password" required>
    <button type="submit">Login</button>
  </form>

  <script>
    document.getElementById('loginForm').addEventListener('submit', async (e) => {
      e.preventDefault(); // 阻止表单默认提交行为
      
      const formData = new FormData(e.target);
      const loginData = {
        Username: formData.get('Username'),
        Password: formData.get('Password')
      };

      try {
        const response = await fetch('/home', {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json'
          },
          body: JSON.stringify(loginData)
        });

        const result = await response.json();
        if (result.authsuccess) {
          // 把Token存入localStorage,页面刷新也不会丢失
          localStorage.setItem('jwtToken', result.token);
          // 跳转到受保护的主页
          window.location.href = '/home';
        } else {
          alert(result.description);
        }
      } catch (err) {
        console.error('登录请求出错:', err);
      }
    });
  </script>
</body>
</html>

主页(home.ejs)携带Token请求示例:

如果主页需要调用其他受保护的API,要从localStorage取出Token,放到Authorization请求头里:

<!DOCTYPE html>
<html>
<head>
  <title>Home</title>
</head>
<body>
  <h1>欢迎回来,<%= user %>!</h1>
  <button id="fetchDataBtn">获取受保护数据</button>

  <script>
    document.getElementById('fetchDataBtn').addEventListener('click', async () => {
      const token = localStorage.getItem('jwtToken');
      if (!token) {
        alert('未检测到Token,请重新登录');
        window.location.href = '/';
        return;
      }

      try {
        const response = await fetch('/your-protected-api', {
          method: 'GET',
          headers: {
            // 严格遵循JWT的请求头格式:Bearer + 空格 + Token
            'Authorization': `Bearer ${token}`
          }
        });

        if (response.status === 401 || response.status === 403) {
          alert('Token无效或已过期,请重新登录');
          localStorage.removeItem('jwtToken');
          window.location.href = '/';
        } else {
          const data = await response.json();
          console.log('获取到的受保护数据:', data);
        }
      } catch (err) {
        console.error('请求出错:', err);
      }
    });
  </script>
</body>
</html>
核心知识点总结
  • Token存储:用localStorage.setItem('key', token)把Token存在浏览器本地,优点是页面刷新、关闭浏览器再打开都能保留;如果是敏感场景,也可以用sessionStorage(关闭页面就消失)或者HttpOnly Cookie(更安全,前端无法直接操作)。
  • 请求头规范:JWT的标准传递方式是放在Authorization请求头里,格式必须是Bearer <你的Token>,后端通过req.headers['authorization']获取后拆分出Token。
  • 后端验证流程:先检查请求头有没有Token→没有返回401→有Token就用jwt.verify验证→验证失败返回403→验证成功处理请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:38:22