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

浏览器端JWT令牌传递问题:页面请求403错误及前置验证需求

浏览器端JWT令牌发送与页面权限验证问题

问题现象

  • Postman请求正常:携带Authorization头发送GET请求获取页面时,过滤器仅被调用一次,且成功获取到令牌,后端日志如下:
2024-06-26 17:33:53.036  INFO 6856 --- [nio-8080-exec-3] u.d.P.security.JWTTokenConfig                    : Filter starts
2024-06-26 17:33:53.037  INFO 6856 --- [nio-8080-exec-3] u.d.P.security.JWTTokenConfig                    : Jwt Token: Bearer         eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3MTk0MTE4MDYsImlhdCI6MTcx        OTQwODgwNn0.YOdWUsdkTl4E4ucZ1gjk8sAYKaBMxrsVET5m6rnRXEg
2024-06-26 17:33:53.037  INFO 6856 --- [nio-8080-exec-3] u.d.P.security.JWTTokenConfig                    : Received JWT token:         eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3MTk0MTE4MDYsImlhdCI6MTcx        OTQwODgwNn0.YOdWUsdkTl4E4ucZ1gjk8sAYKaBMxrsVET5m6rnRXEg
  • 浏览器刷新页面异常:过滤器被调用三次,仅第二次请求获取到令牌;若将/admin_office端点设为受保护,过滤器仅被调用一次且未获取到令牌,前端收到403错误。

当前浏览器页面代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Office Page</title>
    <script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
</head>
<body>
<h1>Welcome to Admin Office</h1>
<script>
 function getCookie(name) {
  let cookieArr = document.cookie.split(";");

  for(let i = 0; i < cookieArr.length; i++) {
    let cookiePair = cookieArr[i].split("=");

    if(name == cookiePair[0].trim()) {
      return decodeURIComponent(cookiePair[1]);
    }
  }

  return null;
}
let jwtToken = getCookie("JWT_TOKEN");
console.log('token '+jwtToken);


fetch('/admin_office', {
    method: 'GET',
    headers: {
        'Content-Type': 'application/json',
        'Authorization': 'Bearer ' + jwtToken
    }
})
.then(response => {
    if (!response.ok) {
        throw new Error('Network response was not ok');
    }
    return response.text();
})
.then(data => {
    console.log('Server response:',jwtToken );
})
.catch(error => {
    console.error('Error sending token to server:', error);
});
</script>
</body>
</html>

浏览器请求时后端日志

2024-06-26 17:40:50.160  INFO 6856 --- [nio-8080-exec-5] u.d.P.security.JWTTokenConfig                    : Filter starts
2024-06-26 17:40:50.162  INFO 6856 --- [nio-8080-exec-5] u.d.P.security.JWTTokenConfig                    : Jwt Token: null
2024-06-26 17:40:50.195  INFO 6856 --- [nio-8080-exec-6] u.d.P.security.JWTTokenConfig                    : Filter starts
2024-06-26 17:40:50.195  INFO 6856 --- [nio-8080-exec-6] u.d.P.security.JWTTokenConfig                    : Jwt Token: Bearer         eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3MTk0MTUwODYsImlhdCI6MT        cxOTQxMjA4Nn0.Uwgj-5TuQnFtRxOQBnSVkIiBzTv4hg9swbAXHRX7dec
2024-06-26 17:40:50.196  INFO 6856 --- [nio-8080-exec-6] u.d.P.security.JWTTokenConfig                    : Received JWT token:         eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiIxIiwicm9sZXMiOlsiUk9MRV9BRE1JTiJdLCJleHAiOjE3MTk0MTUwODYsImlhdCI6MT        cxOTQxMjA4Nn0.Uwgj-5TuQnFtRxOQBnSVkIiBzTv4hg9swbAXHRX7dec
2024-06-26 17:40:50.201  INFO 6856 --- [nio-8080-exec-6]         u.d.PetMusicStorage.service.JWTService   : Parsed roles from token: [ROLE_ADMIN]
2024-06-26 17:40:50.201  INFO 6856 --- [nio-8080-exec-7] u.d.P.security.JWTTokenConfig                    : Filter starts
2024-06-26 17:40:50.202  INFO 6856 --- [nio-8080-exec-7] u.d.P.security.JWTTokenConfig            : Jwt Token: null
2024-06-26 17:40:50.203  INFO 6856 --- [nio-8080-exec-6] u.d.P.security.JWTTokenConfig                    : User 1 with roles [ROLE_ADMIN]

问题根源

浏览器刷新页面时,首次请求是获取HTML文件的GET请求,此时前端脚本尚未执行,无法自动添加Authorization请求头,导致该请求无令牌,被过滤器拦截。后续脚本执行后发送的fetch请求才带上令牌,但当端点受保护时,初始页面请求已被拒绝,返回403错误。

而Postman请求是直接在请求头中携带令牌,因此一次请求即可通过验证。

解决方案

方案1:初始页面请求携带令牌(推荐)

修改前端逻辑,在页面加载时先从Cookie获取令牌,携带令牌请求页面内容,根据后端响应展示对应内容:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Admin Office Page</title>
</head>
<body>
    <div id="app"></div>
    <script>
        function getCookie(name) {
            let cookieArr = document.cookie.split(";");
            for(let i = 0; i < cookieArr.length; i++) {
                let cookiePair = cookieArr[i].split("=");
                if(name == cookiePair[0].trim()) {
                    return decodeURIComponent(cookiePair[1]);
                }
            }
            return null;
        }

        // 页面初始化函数:验证令牌并获取页面内容
        async function initAdminPage() {
            const jwtToken = getCookie("JWT_TOKEN");
            const appContainer = document.getElementById('app');

            // 无令牌直接提示
            if (!jwtToken) {
                appContainer.innerHTML = '<h1>未登录,请先登录</h1>';
                return;
            }

            try {
                // 携带令牌请求页面
                const response = await fetch('/admin_office', {
                    method: 'GET',
                    headers: {
                        'Authorization': `Bearer ${jwtToken}`
                    }
                });

                // 处理响应
                if (!response.ok) {
                    if (response.status === 403) {
                        appContainer.innerHTML = '<h1>权限不足,无法访问此页面</h1>';
                    } else {
                        throw new Error(`请求失败,状态码:${response.status}`);
                    }
                    return;
                }

                // 渲染页面内容
                const pageContent = await response.text();
                appContainer.innerHTML = pageContent;
            } catch (error) {
                appContainer.innerHTML = `<h1>页面加载失败:${error.message}</h1>`;
                console.error('初始化错误:', error);
            }
        }

        // 页面加载完成后执行初始化
        window.addEventListener('load', initAdminPage);
    </script>
</body>
</html>

方案2:后端直接拦截无令牌请求

确保后端/admin_office接口为受保护端点,仅接受携带有效JWT令牌的请求:

  • 令牌有效:返回完整的管理页面HTML
  • 令牌缺失/无效:直接返回403错误页面或重定向到登录页

同时,前端可通过全局请求拦截器自动给所有请求添加令牌:

function getCookie(name) {
    let cookieArr = document.cookie.split(";");
    for(let i = 0; i < cookieArr.length; i++) {
        let cookiePair = cookieArr[i].split("=");
        if(name == cookiePair[0].trim()) {
            return decodeURIComponent(cookiePair[1]);
        }
    }
    return null;
}

// 全局拦截所有fetch请求,自动添加Authorization头
const originalFetch = window.fetch;
window.fetch = async function(url, options = {}) {
    const jwtToken = getCookie("JWT_TOKEN");
    if (jwtToken) {
        options.headers = {
            ...options.headers,
            'Authorization': `Bearer ${jwtToken}`
        };
    }
    return originalFetch(url, options);
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.22 01:17:02