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

JWT认证异常:关闭标签页后仍可访问受保护页面求助

问题分析与解决方案

核心问题

  1. 会话Cookie生命周期误解:登录时设置的JWT Cookie属于会话Cookie(未指定expires或maxAge),这类Cookie仅在整个浏览器进程关闭时才会失效,单个标签页关闭不会清除Cookie,因此新标签页请求仍会携带Cookie通过认证。
  2. HTTPOnly Cookie可见性误解:由于Cookie设置了httpOnly: true,前端通过document.cookie无法看到该Cookie,但浏览器在发送请求时会自动携带,导致你误以为Cookie不存在,实际认证仍能通过。
  3. 登录逻辑判断错误:if(findData==={})永远为false,对象引用对比无法匹配空对象,应改用if(!findData)判断用户是否存在。
  4. 中间件错误操作:认证通过后执行res.cookie('jwt',' ',{maxAge:1})会立即清空Cookie,导致用户仅能访问一次受保护页面,不符合需求。

修复步骤

1. 修正登录逻辑的判断错误

修改登录接口中的用户存在判断,并配置Cookie实现标签页关闭失效:

app.post('/login/recorded',async(req,res)=>{
    const findData=await RegisterationModel.findOne({email:req.body.email});
    try{
        console.log(findData);
        // 替换原错误判断,正确检测用户是否存在
        if(!findData){
            res.send("not found");
            return; // 提前返回,避免后续代码执行
        }
        if(findData.email===req.body.email && findData.password===req.body.password){
            const token = await findData.generateAuthToken();
            res.cookie('jwt',token,{
                httpOnly: true,
                // 配置Cookie与标签页绑定,关闭标签页自动失效(Chrome 104+支持)
                sameSite: 'Strict',
                partitioned: true,
                // 生产环境需开启secure(仅HTTPS下生效)
                secure: process.env.NODE_ENV === 'production'
            });
            res.redirect('/index');
            console.log(token)
        }
        else{
            res.send("invalid");
        }
    }
    catch(error){
        console.log(error);
    }
})

2. 修正认证中间件的错误操作

移除中间件中清空Cookie的代码,确保登录后可正常访问受保护页面:

const auth =async(req,res,next)=>{
    try{
        console.log("auth")
        const token=req.cookies.jwt;
        // 主动检测token是否存在,提前抛出错误
        if(!token){
            throw new Error('未提供认证Token');
        }
        const verifyUser=jwt.verify(token,'helloworld');
        const user=await RegisterationModel.findOne({_id:verifyUser._id});
        console.log(verifyUser);
        // 移除清空Cookie的错误代码
        next();
    }
    catch(error){
        res.status(401).send(error.message || '认证失败');
        console.log(error)
    }
}

3. 兼容其他浏览器的可选方案

若需兼容不支持partitioned属性的浏览器,可结合前端sessionStorage做辅助校验:

  • 在index.hbs中添加前端脚本:
    <html>
    <head>
        <title>Index Filee</title>
    </head>
    <body>
        <ul>
            <li><a href="/secretpage">Secret Page</a></li>
            <li><a href="/login">Login</a></li>
            <li><a href="/register">Register</a></li>
        </ul>
        <script>
            // 生成标签页唯一认证密钥
            if (!sessionStorage.getItem('tabAuthKey')) {
                sessionStorage.setItem('tabAuthKey', Math.random().toString(36).substring(2));
            }
            // 拦截所有请求,携带密钥到后端(示例用fetch拦截)
            const originalFetch = window.fetch;
            window.fetch = function(url, options = {}) {
                options.headers = options.headers || {};
                options.headers['X-Tab-Auth-Key'] = sessionStorage.getItem('tabAuthKey');
                return originalFetch(url, options);
            };
        </script>
    </body>
    </html>
    
  • 中间件新增密钥校验逻辑(需配合服务器存储关联关系,如Redis):
    const auth =async(req,res,next)=>{
        try{
            console.log("auth")
            const token=req.cookies.jwt;
            const tabKey=req.headers['x-tab-auth-key'];
            
            if(!token || !tabKey){
                throw new Error('未提供完整认证信息');
            }
            // 此处需从存储中校验tabKey与用户的关联关系,示例省略存储逻辑
            const verifyUser=jwt.verify(token,'helloworld');
            const user=await RegisterationModel.findOne({_id:verifyUser._id});
            
            console.log(verifyUser);
            next();
        }
        catch(error){
            res.status(401).send(error.message || '认证失败');
            console.log(error)
        }
    }
    

验证效果

  1. 登录成功后,可正常访问/secretpage。
  2. 关闭当前标签页,重新打开新标签页访问/secretpage,浏览器会因无有效Cookie(或密钥校验失败)返回401认证错误,无法访问受保护页面。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 21:18:16