Node.js学习JWT遇阻:如何在Header传递JWT并存储到浏览器localStorage
嘿,我帮你理清楚这个问题,你现在卡在JWT的前端存储和请求头传递环节,而且代码里还有几个小bug得先搞定,一步步来:
第一步:先修正代码里的致命Bug
你的routes/index.js里的登录函数有两个明显问题,导致Token根本没法正常返回给前端:
- 你写了
response.json(...),但变量名应该是res,这会直接报错; - 你先执行了
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
相关产品推荐
相关产品推荐

