
本文详解前端 html 页面如何可靠地将 jwt token(存储于 cookie)发送至后端,并解决因请求顺序、token 读取位置错误导致的 403 访问拒绝问题。核心在于:后端过滤器需从 cookie 而非 authorization 请求头读取 token,尤其当页面首次加载时。
本文详解前端 html 页面如何可靠地将 jwt token(存储于 cookie)发送至后端,并解决因请求顺序、token 读取位置错误导致的 403 访问拒绝问题。核心在于:后端过滤器需从 cookie 而非 authorization 请求头读取 token,尤其当页面首次加载时。
在典型的前后端分离或服务端渲染混合场景中,浏览器首次访问 /admin_office 这类受保护页面时,会触发两次关键请求:
-
HTML 文档请求(GET
/admin_office):浏览器直接向服务器请求该路径的 HTML 内容;此时若后端安全过滤器仅检查Authorization: Bearer请求头,而 Token 实际以 Cookie(如JWT_TOKEN=xxx)形式存在,则必然读取为null→ 触发 403; -
页面内脚本发起的 API 请求(如
fetch('/admin_office')):此时 JavaScript 手动读取 Cookie 并显式设置Authorization头,后端才可成功解析。
你日志中出现三次过滤器调用,正是这一流程的体现:第一次是 HTML 请求(无 Authorization 头,Cookie 未被读取)、第二次是脚本发起的 fetch 请求(手动带了头)、第三次可能是资源预加载或重复请求。而真正决定页面能否渲染的是第一次 HTML 请求的鉴权结果——它必须成功,否则用户根本看不到页面内容。
✅ 正确做法:后端过滤器应优先从 Cookie 中提取 JWT Token,兼容“页面直访”场景。以下是 Spring Boot 中 JWTTokenConfig 过滤器的关键修复代码:
@Override
protected void doFilterInternal(HttpServletRequest request,
HttpServletResponse response,
FilterChain filterChain) throws IOException, ServletException {
String authHeader = null;
// ✅ 优先尝试从 Cookie 中读取 JWT_TOKEN
Cookie[] cookies = request.getCookies();
if (cookies != null) {
authHeader = Arrays.stream(cookies)
.filter(cookie -> "JWT_TOKEN".equals(cookie.getName()))
.findAny()
.map(cookie -> "Bearer " + cookie.getValue()) // 统一格式,便于后续解析
.orElse(null);
}
// ⚠️ 备用:仍支持从 Authorization Header 读取(兼容 API 调用)
if (authHeader == null) {
authHeader = request.getHeader("Authorization");
}
logger.info("Jwt Token: {}", authHeader);
if (authHeader != null && authHeader.startsWith("Bearer ")) {
String token = authHeader.substring(7).trim();
try {
// 解析 token、校验签名、提取用户信息与角色...
String username = jwtService.extractUsername(token);
List<string> roles = jwtService.extractRoles(token);
// 构建 Authentication 并存入 SecurityContext...
} catch (Exception e) {
logger.warn("Invalid JWT token", e);
}
}
filterChain.doFilter(request, response);
}</string>
? 重要注意事项:
-
Cookie 安全属性:确保
JWT_TOKENCookie 设置了HttpOnly=false(否则 JS 无法读取,但此处后端读取不受影响),同时建议启用Secure(仅 HTTPS 传输)和SameSite=Strict/Lax防 CSRF; -
前端无需主动 fetch:修复后端后,浏览器直接访问
/admin_office即可完成鉴权并返回 HTML,无需再依赖<script></script>中的fetch()—— 该逻辑可移除或仅用于后续 AJAX 数据请求; -
避免重复鉴权:若使用 Spring Security,建议将该过滤器置于
UsernamePasswordAuthenticationFilter之前,并确保不与BearerTokenAuthenticationFilter冲突; -
调试技巧:在过滤器开头添加
logger.debug("Request URI: {}, Method: {}, Cookies: {}", request.getRequestURI(), request.getMethod(), Arrays.toString(request.getCookies()));可快速定位 Token 来源。
总结:JWT 的传递方式必须与实际存储机制严格匹配。当 Token 存于 Cookie 时,后端守门员(Filter)必须“低头看 Cookie”,而非只“抬头看 Header”。这一微小调整,即可让受保护页面实现真正的无缝访问与安全兜底。











