【问题标题】:Refresh token how to handle POST routing刷新令牌如何处理 POST 路由
【发布时间】:2021-06-11 07:20:07
【问题描述】:

我是 JWT 和用于用户验证和登录的令牌的新手。我为 Node JS (NPM) 使用了以下扩展

var jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser')
require('dotenv').config();
// Express ..

我已经有一个登录 MongoDB(Node JS 作为服务器)用户,检查电子邮件和密码,然后设置一个带有访问令牌和刷新令牌的 cookie。

我的登录密码是这样的

//create the access token with the shorter lifespan
let accessToken = jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, {
    algorithm: "HS256",
    expiresIn: process.env.ACCESS_TOKEN_LIFE
})

//create the refresh token with the longer lifespan
let refreshToken = jwt.sign(payload, process.env.REFRESH_TOKEN_SECRET, {
    algorithm: "HS256",
    expiresIn: process.env.REFRESH_TOKEN_LIFE
})

//send the access token to the client inside a cookie
res.cookie("_login", accessToken, {secure: true, httpOnly: true})
res.send()

这是刷新令牌发布的部分

exports.refresh = function (req, res, next){

console.log("Test");

let accessToken = req.cookies._login

if (!accessToken){
    return res.status(403).send()
}

let payload
try{
    payload = jwt.verify(accessToken, process.env.ACCESS_TOKEN_SECRET)
 }
catch(e){
    return res.status(401).send()
}

//retrieve the refresh token from the users array
let refreshToken = payload.email.refreshToken

//verify the refresh token
try{
    jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET)
}
catch(e){
    return res.status(401).send()
}

let newToken = jwt.sign(payload, process.env.ACCESS_TOKEN_SECRET, 
{
    algorithm: "HS256",
    expiresIn: process.env.ACCESS_TOKEN_LIFE
})

res.cookie("_login", newToken, {secure: true, httpOnly: true})
res.send()

我现在的问题是,由于我在很多教程和指南中看到它们也可以通过 POST 使用刷新令牌,我该如何与用户一起处理?

客户端是否会发送 AJAX 或发布到中间件以检查访问令牌

-> 如果访问令牌已过期

--> 代码自动获取刷新令牌并发出新的访问令牌并给出OK?

客户端发送到检查访问令牌的中间件

-> 访问令牌已过期(结果给用户)

-> 客户端现在向 /refresh-token 结果发布请求 = 新的访问和刷新令牌

-> 然后再次向原始中间件发布请求,并使用新的发布请求?

这里的程序是什么,我找不到任何解决方法。

【问题讨论】:

  • 您使用的前端是什么?反应?或者只是一般的 JavaScript?如果您碰巧使用与我相同的框架,我也许可以提供更多指点。
  • 嗨@NicholasD 我目前一般使用Javascript和iquery

标签: node.js jwt


【解决方案1】:

请记住,我的回答是基于我的经验。如果我碰巧在我的方式上犯了错误,任何人都可以随意编辑。

所以,为了处理刷新令牌,我使用这种方式:

  • 当用户成功登录后,JWT(包含用户的身份验证)和刷新令牌(包含用户的刷新令牌)将被放置在用户的 cookie 中(和你一样)。
  • 用户将在您的 Web 应用程序中执行他/她的操作,直到他/她关闭浏览器而不退出。
  • 请记住,JWT 始终有到期日期 - 将牢记此到期日期。
  • 在每个请求中,您将发送特定的 JWT(包含用户的身份验证)和刷新令牌到中间件,您将在其中发出 POST 请求。 如果 JWT 已过期,请选择刷新令牌并致电您的 /refresh-token-result 以获取新令牌。 否则,不要对刷新令牌执行任何操作并继续执行您的请求。
  • 确保您的/refresh-token-result 接受请求令牌。端点将检查其有效性并返回一个新的访问令牌。
  • 如果刷新令牌已过期,请注销用户。这是出于安全原因,这很重要!

哦,当用户注销时,请确保您的用户令牌和用户的刷新令牌都被正确撤销,通常通过更改 cookie 值和expiresIn 属性。对我来说,我通常将两个 cookie 值都更改为 loggedOut,并将 expiresIn 设置为 5 秒。

或者,如果您正在使用 React(附加答案),您可以这样做:

  • 如果用户访问您的网站,并且 JWT 到期日期即将到期,您可以简单地使用 useEffect() 挂钩来更新您的访问令牌。

TL;DR:你的第二种方式已经很好了。

编辑:示例伪代码可以帮助您。不要立即复制粘贴,它很可能不起作用,但它应该让您大致了解事情的工作原理。

// middleware.js
const { token, refreshToken } = req.cookies;

// 1. If the token has not expired, call 'next()'
// assume 'isExpired' returns boolean: true or false depending on the state of your token.
if (!token.isExpired()) {
  return next();
}

// 2. If the token has expired AND the refreshToken has not expired, issue a new token, THEN call 'next()'
if (token.isExpired() && !refreshToken.isExpired()) {
  await issueToken();
  return next();
}

// 3. Else, logout the user. I'll keep this one short.
await logoutUser();

res.status(401).json({
  status: 'fail',
  message: 'Your access has expired! Please log in again!',
});

这是你的控制器。

// controller.js
const getAllComments = async (req, res, next) => {
  const comments = await Comment.find();
  
  res.status(200).json({
    status: 'success',
    data: comments,
  });
}

而且,您的路线应该是这样的。

// this import might be unresolved - keep in mind!
const middleware = require('./middleware');
const getAllComments = require('./controllers');

router.get('/api/v1/comments/', middleware, 
checkToken, getAllComments); // assume checkToken is your function to check for a token's validity.

请记住,我没有包含错误处理以使此示例简短。

【讨论】:

  • 非常感谢您的解释!我有以下关于“如果 JWT 已过期,请选择刷新令牌并调用您的 /refresh-token-result”的问题所以客户端向 /cmets 发出一个发布请求作为示例,我的中间件脚本验证功能可以检查令牌。那么我可以在验证功能中执行所有这些操作吗,或者如何以 Axios 为例将带有正文和 cookie 的另一篇帖子发送到 /refresh-token-result 或者您的意思是,客户端将收到(错误令牌已过期)并再次发送/refresh-token-result 的新帖子?
  • 您的中间件脚本应该独立于/comments 路由。我将编辑我的答案以获得伪代码解释。希望对你有帮助!
  • 哇,这很有帮助!非常感谢
猜你喜欢
  • 1970-01-01
  • 2014-08-01
  • 1970-01-01
  • 2014-06-15
  • 1970-01-01
  • 1970-01-01
  • 2020-09-11
  • 2017-07-18
  • 1970-01-01
相关资源
最近更新 更多