简体   繁体   English

如何在 React.js 应用程序中刷新 JWT 令牌?

[英]How to refresh JWT tokens in React.js Application?

I checked all the similar questions here but none has what I need.我在这里检查了所有类似的问题,但没有一个是我需要的。 I'm securing the routs in my App and sending the JWT with every request and everything is fine here.我正在保护我的应用程序中的路由,并随每个请求发送 JWT,这里一切正常。 The issue is when the JWT expires, instead of logging out the user, I need to know how to refresh that token and keep the user logged in.问题是当 JWT 到期时,我需要知道如何刷新该令牌并使用户保持登录状态,而不是注销用户。

Everyone is talking about creating a "Middleware" that handles that, but no one says how to create that middleware and what's in it?每个人都在谈论创建一个处理该问题的“中间件”,但没有人说如何创建该中间件以及其中包含什么?

So, what is the best practice in doing that?那么,这样做的最佳实践是什么? Should I check for JWT expiration date before sending any request?我应该在发送任何请求之前检查 JWT 的到期日期吗? or should I wait for a "401" response then try to refresh the token (which I don't know how to do), or what exactly?或者我应该等待“401”响应然后尝试刷新令牌(我不知道该怎么做),或者究竟是什么?

If anyone has a working example of such a middleware or a package or a project on Github that can help me with this it would be great.如果有人在 Github 上有这样的中间件或包或项目的工作示例可以帮助我解决这个问题,那就太好了。

I'm only interested in the front-end part of the process, what to send from react and what should I expect to receive and what to do with it.我只对流程的前端部分感兴趣,从反应发送什么以及我应该收到什么以及如何处理它。

If you are using Axios (which I highly recommend), you can declare your token refreshing behaviours in the response's interceptors .如果您正在使用 Axios(我强烈推荐),您可以在响应的拦截器中声明您的令牌刷新行为。 This will apply to all https requests made by Axios.这将适用于 Axios 发出的所有 https 请求。

The process is something like这个过程就像

  1. Checking if the error status is 401检查错误状态是否为 401
    • If there is a valid refresh token: use it to get the access token如果有一个有效的刷新令牌:使用它来获取访问令牌
    • if there is no valid refresh token: log the user out and return如果没有有效的刷新令牌:注销用户并返回
  2. Redo the request again with the new token.使用新令牌再次重做请求。

Here is an example:下面是一个例子:

axios.interceptors.response.use(
  (response) => {
    return response
  },
  (error) => {
    return new Promise((resolve) => {
      const originalRequest = error.config
      const refreshToken = localStorage.get('refresh_token')
      if (error.response && error.response.status === 401 && error.config && !error.config.__isRetryRequest && refreshToken) {
        originalRequest._retry = true

        const response = fetch(api.refreshToken, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
          },
          body: JSON.stringify({
            refresh: refreshToken,
          }),
        })
          .then((res) => res.json())
          .then((res) => {
            localStorage.set(res.access, 'token')

            return axios(originalRequest)
          })
        resolve(response)
      }

      return Promise.reject(error)
    })
  },
)

your middelware should look like this block of code (as example you can use whatever you want)你的中间件应该看起来像这个代码块(例如,你可以使用任何你想要的)

/* eslint-disable */
import request from 'superagent';
function call(meta, token) {
  const method = meta.API_METHOD ? meta.API_METHOD : 'GET';
  let req = request(method, 'http://localhost:8000/' + meta.API_CALL);
  req = req.set({ Authorization: `JWT ${token}` });
  req = meta.API_TYPE ? req.type('Content-Type', meta.API_TYPE) : req.set('Content-Type', 'application/json');
  if (meta.API_PAYLOAD) {
    req = req.send(meta.API_PAYLOAD);
  }
  if (meta.API_QUERY) {
    req.query(meta.API_QUERY);
  }

  return req;
}

export default store => next => action => {
  const state = store.getState();
  const token = state.logged && state.logged.get('token') ?
    state.logged.get('token') : 'eyJhbGciOiJIUzUxMiJ9';
  if (action.meta && action.meta.API_CALL) {
    call(action.meta, token)
      .then((res) => {
        store.dispatch({
          type: action.meta.API_SUCCESS,
          result: res.body,
        });
      })
      .catch(({ status, response }) => {
        if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
          return store.dispatch({
            type: action.meta.API_ERRORS[status],
            result: response.body,
          });
        }
        if (action.meta.API_ERRORS && action.meta.API_ERRORS[status] === '401') {
          /*call the refresh token api*/
          call(<Your Meta for refreshing>, <expiredtoken>)
                .then((res) => {
                    store.dispatch({
                    type: action.meta.API_SUCCESS,
                    result: res.body,
                    });
                })
                .catch(({ status, response }) => {
                    if (action.meta.API_ERRORS && action.meta.API_ERRORS[status]) {
                    return store.dispatch({
                        type: action.meta.API_ERRORS[status],
                        result: response.body,
                    });
                    }
                    throw response;
                });
        }
        throw response;
      });
  }
  return next(action);
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM