前端获取并存储JWT令牌以解决403错误的问题求助
前端获取并存储JWT令牌以解决403错误的问题求助
兄弟,看你描述的情况,第一次处理JWT确实容易卡在前后端衔接的地方,我帮你一步步拆解问题,解决这个403的问题:
首先,你现在的核心问题是后端注册成功后,没有把JWT正确传递给前端,导致后续请求没有携带认证信息,触发403。而且你之前用的是后端重定向,这种方式前端拿不到响应里的JWT,得调整一下逻辑:
一、先调整后端RegisterController的返回逻辑
原来的重定向操作没法让前端拿到JWT,你需要改成返回包含JWT的响应,或者把JWT放到安全的Cookie里,分两种情况:
情况1:前后端分离/用AJAX提交注册(推荐)
把注册接口改成返回JSON格式的响应,包含JWT和跳转地址:
@PostMapping public ResponseEntity<Map<String, String>> register(@RequestBody UserRegistrationDto registrationDto) { // 你的注册逻辑:调用userService完成注册 User registeredUser = userService.register(registrationDto); // 生成JWT令牌 String jwtToken = jwtTokenService.generateToken(registeredUser); // 返回token和跳转地址 return ResponseEntity.ok(Map.of( "token", jwtToken, "redirectUrl", "/personal_office" )); }
情况2:服务端渲染页面(用Cookie传递,更安全)
如果是传统服务端渲染(比如Thymeleaf、JSP),可以把JWT放到HttpOnly Cookie里,浏览器会自动携带到后续请求:
@PostMapping public String register(UserRegistrationDto registrationDto, HttpServletResponse response) { User registeredUser = userService.register(registrationDto); String jwtToken = jwtTokenService.generateToken(registeredUser); // 创建HttpOnly Cookie,防止XSS攻击 Cookie jwtCookie = new Cookie("auth_token", jwtToken); jwtCookie.setHttpOnly(true); // 前端JS无法读取,更安全 jwtCookie.setPath("/"); // 全站请求都携带 jwtCookie.setMaxAge(24 * 60 * 60); // 有效期1天 // 生产环境记得开启Secure,只在HTTPS下传输 // jwtCookie.setSecure(true); response.addCookie(jwtCookie); return "redirect:/personal_office"; }
二、前端处理JWT的存储和携带
针对情况1(AJAX提交):
- 阻止默认表单提交:用JS监听注册表单的提交事件,用AJAX发送请求,这样能拿到后端返回的JWT:
// 假设你的注册表单id是register-form document.getElementById('register-form').addEventListener('submit', async (e) => { e.preventDefault(); // 阻止页面刷新 // 收集表单数据 const formData = new FormData(e.target); const userInfo = Object.fromEntries(formData); try { const response = await fetch('/register', { method: 'POST', headers: { 'Content-Type': 'application/json', }, body: JSON.stringify(userInfo), }); if (response.ok) { const { token, redirectUrl } = await response.json(); // 把JWT存到localStorage localStorage.setItem('auth_token', token); // 前端自己跳转到个人中心 window.location.href = redirectUrl; } else { // 处理注册失败的提示 const errorMsg = await response.text(); alert(`注册失败:${errorMsg}`); } } catch (err) { console.error('注册请求出错:', err); alert('网络异常,请重试'); } });
- 后续请求携带JWT:访问需要认证的页面/接口时,在请求头里带上
Authorization: Bearer <token>:
// 封装一个带认证的请求函数 async function sendAuthenticatedRequest(url, options = {}) { const token = localStorage.getItem('auth_token'); if (!token) { // 没有token,跳回注册页 window.location.href = '/host_page'; return; } // 合并请求头,加上Authorization const authOptions = { ...options, headers: { ...options.headers, 'Authorization': `Bearer ${token}`, }, }; const response = await fetch(url, authOptions); if (response.status === 403 || response.status === 401) { // Token失效或无效,清除存储并跳转 localStorage.removeItem('auth_token'); window.location.href = '/host_page'; alert('登录状态已失效,请重新注册'); } return response; } // 比如访问个人中心的数据 async function loadPersonalOfficeData() { const response = await sendAuthenticatedRequest('/personal_office/data'); if (response.ok) { const data = await response.json(); // 渲染页面数据 console.log(data); } } // 页面加载时调用 window.addEventListener('load', loadPersonalOfficeData);
针对情况2(Cookie传递):
这种情况前端几乎不用做额外操作,浏览器会自动把HttpOnly Cookie带到所有同域请求里,你只需要确保后端的安全配置能正确从Cookie中提取JWT进行验证即可。
三、关键注意事项
- 安全问题:用localStorage存JWT有XSS风险,如果网站存在XSS漏洞,攻击者能窃取token;用HttpOnly Cookie更安全,但前端无法直接操作token(比如刷新token需要后端单独处理)。
- Token过期处理:后端要配置Token的过期时间,前端在收到401/403响应时,要清除存储的token并跳转到注册页。
- 后端安全配置:确保你的Spring Security配置正确,比如允许OPTIONS请求(如果用CORS),配置JWT过滤器从请求头(情况1)或Cookie(情况2)中提取Token进行认证。
备注:内容来源于stack exchange,提问作者PavelPavlik
相关产品推荐
相关产品推荐

