How I understand jwt based authentication should work:

  • 客户端将登录凭据发送到服务器 .

  • 服务器验证凭据是否正确并使用签名的jwt令牌和刷新令牌进行响应,同时还将刷新令牌存储在数据库中 .

  • 客户端在所有请求中使用jwt令牌作为Authentication头 .

  • 当jwt令牌已过期时,服务器以 401 Unauthorized 响应 .

  • 客户端使用Authentication头中的刷新令牌发送刷新jwt令牌的请求 .

  • 服务器检查刷新令牌是否存在于数据库中且未过期 . 然后使用新的jwt令牌进行响应

  • 客户端可以继续使用新令牌进行请求 .

How I want to implement it:

如果上面的描述是正确的,那么将刷新令牌作为签名的jwt令牌的有效负载是否有任何问题?:

function signToken(id, role, refresh_token) {
    return jwt.sign(
        {
            _id: id,
            role: role,
            refresh_token: refresh_token
        },
        config.jwt.secret,
        {
            expiresIn: 60*60*24, // expires in 1 day
        }
    );
}

并且以这种方式总是在每个请求中发送刷新令牌和jwt令牌?通过执行此操作,客户端不必使用刷新令牌发送单独的请求以获取新的jwt令牌:

  • 与上述相同

  • 与上述相同

  • 与上述相同

  • 当jwt令牌已过期时,服务器从jwt令牌中挑选刷新令牌,并检查它是否存在于数据库中且未过期 .

  • Server使用requesed资源响应新的jwt令牌 .

  • 客户端看到响应中有新令牌并将其保存以供进一步请求 .

Auth中间件看起来像这样:

function authenticate (req, res, next) {

    // Token attached to request in previous middleware
    let token = req.token

    // verifies secret and checks exp
    jwt.verify(token, config.jwt.secret, {ignoreExpiration: true}, (err, decoded) => {
        if (err) {
            return res.status(500).json({ success: false, message: err.message });
        }
        //Expired token, try to refresh
        if(decoded.exp*1000 < Date.now()){
            User.findById(decoded._id, (err, user) => {
                if(err) {return res.send(err);}
                if(!user){
                    return res.status(500).json({ success: false, message: 'Token owner not found.' });
                }

                //if refresh token found, and not expired, refresh expiry time
                let isValidToken = _(user.refresh_tokens)
                                        .filter( (token) => {return token.expires>Date.now()} )
                                        .any({token: decoded.refresh_token});
                if(!isValidToken){
                    req.user = {role: 'Guest'};
                    return next();
                }

                let newToken = signToken(decoded._id, decoded.role, decoded.refresh_token);
                req.token = newToken;
                req.user = decoded;
                return next();
            })
        } else {
            // if everything is good, save to request for use in other routes
            req.user = decoded;
            return next();
        }
    });
}