【问题标题】:is there a way to know why cookie does not get sent to the server有没有办法知道为什么 cookie 没有被发送到服务器
【发布时间】:2022-10-24 16:56:30
【问题描述】:

拜托,我正在做一个节点具有注册和登录功能的 REST api,

  • 当用户登录时,他们会获得一个 accessToken。
  • 其次,保存包含refreshToken 的cookie,以使用户能够向/refresh 端点请求新的accessToken。

这是我的问题;当用户登录时,我可以看到 cookie,但是在对其他路由的后续请求之后,cookie消失并且不再发送到服务器,从而阻止我向 /refresh 端点请求新的 accessToken。

// log-in controller

const User = require('../model/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');

const handleLogin = async (req, res) => {
    const { user, pwd } = req.body;
    if (!user || !pwd) return res.status(400).json({ 'message': 'Username and password are required.' });

    const foundUser = await User.findOne({ username: user }).exec();
    if (!foundUser) return res.sendStatus(401); //Unauthorized 
    // evaluate password 
    const match = await bcrypt.compare(pwd, foundUser.password);
    if (match) {
        const roles = Object.values(foundUser.roles).filter(Boolean);
        // create JWTs
        const accessToken = jwt.sign(
            {
                "UserInfo": {
                    "username": foundUser.username,
                    "roles": roles
                }
            },
            process.env.ACCESS_TOKEN_SECRET,
            { expiresIn: '10s' }
        );
        const refreshToken = jwt.sign(
            { "username": foundUser.username },
            process.env.REFRESH_TOKEN_SECRET,
            { expiresIn: '1d' }
        );
        // Saving refreshToken with current user
        foundUser.refreshToken = refreshToken;
        const result = await foundUser.save();
        console.log(result);
        console.log(roles);

        // Creates Secure Cookie with refresh token
        res.cookie('jwt', refreshToken, { httpOnly: true, secure: true, sameSite: 'None', maxAge: 24 * 60 * 60 * 1000 });

        // Send authorization roles and access token to user
        res.json({ roles, accessToken });

    } else {
        res.sendStatus(401);
    }
}

module.exports = { handleLogin };



// refresh endpoint controller

const User = require('../model/User');
const jwt = require('jsonwebtoken');

const handleRefreshToken = async (req, res) => {
    const cookies = req.cookies;
    if (!cookies?.jwt) return res.sendStatus(401);
    const refreshToken = cookies.jwt;

    const foundUser = await User.findOne({ refreshToken }).exec();
    if (!foundUser) return res.sendStatus(403); //Forbidden 
    // evaluate jwt 
    jwt.verify(
        refreshToken,
        process.env.REFRESH_TOKEN_SECRET,
        (err, decoded) => {
            if (err || foundUser.username !== decoded.username) return res.sendStatus(403);
            const roles = Object.values(foundUser.roles);
            const accessToken = jwt.sign(
                {
                    "UserInfo": {
                        "username": decoded.username,
                        "roles": roles
                    }
                },
                process.env.ACCESS_TOKEN_SECRET,
                { expiresIn: '10s' }
            );
            res.json({ roles, accessToken })
        }
    );
}

module.exports = { handleRefreshToken }


【问题讨论】:

  • 这听起来像 cookie 过期了。
  • cookie 不能过期,它设置为一天。
  • 在开发工具中打开网络选项卡并检查请求和响应。必须有一个包含 cookie 的最后一个请求和一个没有 cookie 的第一个请求。在那里您应该找到修改或删除 cookie 的响应。
  • 不得不提的是,我是用迅雷客户端来测试API的,当我查看cookies选项卡时,它显示“No Cookies Available”
  • 刷新令牌不属于 cookie!为什么还要在这一点上使用单独的刷新/访问令牌? evertpot.com/jwt-is-a-bad-default 。为什么不是 OAuth2?不要自己滚动

标签: javascript node.js rest authentication jwt


【解决方案1】:

我遇到了和你一样的问题:迅雷客户端无法在后续请求中发回 cookie。我在 handleLogin 中更改 res.cookie 后解决了这个问题。试试看:

res.cookie('jwt', refreshToken, { httpOnly: true, maxAge: 24 * 60 * 60 * 1000 });

【讨论】:

    【解决方案2】:

    JWT 刷新令牌是一次性的。 因此,在用户登录 JWT 服务器后的代码中,您将获得 10 秒后过期的 accessToken,并刷新您保存到用户浏览器 cookie 中的令牌。 accessToken 过期后,您将使用用户的 refreshToken 生成新的 accessToken。此时您当前的 refreshToken 已过时,当您尝试再生成一个 accessToken(在 10 秒内)时,它将失败。 因此,在 handleRefreshToken() 函数中,您需要生成全新的 refreshToken:

            const refreshToken = jwt.sign(
                { "username": foundUser.username },
                process.env.REFRESH_TOKEN_SECRET,
                { expiresIn: '1d' }
            );
            // Saving refreshToken with current user
            foundUser.refreshToken = refreshToken;
            const result = await foundUser.save();
            console.log(result);
            console.log(roles);
    
            // Creates Secure Cookie with refresh token
            res.cookie('jwt', refreshToken, { httpOnly: true, secure: true, sameSite: 'None', maxAge: 24 * 60 * 60 * 1000 });
    

    【讨论】:

    • 我不明白作者的代码中浏览器cookie是如何被删除的,但无论如何,refreshToken在服务器端是无效的。因此,即使它仍在用户的浏览器中,也没关系
    • 不得不提的是,我正在使用迅雷客户端测试API,当我检查cookies选项卡时,它显示“没有可用的cookies”。
    猜你喜欢
    • 2021-04-28
    • 2012-10-19
    • 1970-01-01
    • 2021-12-10
    • 2015-05-26
    相关资源
    最近更新 更多