【问题标题】:How do I auto-refresh a JWT in redux without breaking async flow?如何在不中断异步流的情况下自动刷新 redux 中的 JWT?
【发布时间】:2019-02-16 07:37:13
【问题描述】:

高级描述

我有一个使用 Google Oauth 的 React/redux/electron 应用程序。我希望能够在访问令牌过期时自动刷新它。我对此进行了研究并使用中间件成功解决了它,但我的解决方案在某些情况下会出错。

我已经实现了一个在每个 API 操作上运行的刷新中间件。它检查访问令牌是否已过期或即将过期。如果是这样,它不会分派它收到的操作,而是分派一个令牌刷新操作并将任何其他操作排队,直到收到新的访问令牌。之后,它调度其队列中的所有操作。

但是,我的一个动作创建者看起来像这样:

function queryThreads(params) {
  return async (dispatch) => {
    const threads = await dispatch(fetchThreads(params))
    const newPageToken = threads.payload.nextPageToken
  }
}

当由于令牌未过期而导致刷新中间件未运行时,threads.payload 将在此处定义,一切都会按预期工作。

但是,当刷新中间件确实运行时,threads.payload 将是 undefined,因为 dispatch 似乎使用令牌刷新操作的值而不是 fetchThreads 操作来解析。

如何确保令牌被刷新(并在state/localStorage 中更新),fetchThreads 与更新的令牌一起调度,threads 变量被分配给正确的解析值答应吗?

项目代码链接

This is my refresh middleware。它的灵感来自this article kmmbvnr

This is the token refresh action creator.

This is the line in my queryThreads action creator 在令牌必须刷新时抛出(threads.payloadundefined)。

This is the reducer where I update state 响应令牌刷新。

This is the middleware where I update localStorage 响应令牌刷新。

【问题讨论】:

  • 你为什么不使用 localStorage 呢?浏览器刷新会丢失 redux 状态
  • 我已经在 localStorage 中存储了令牌。
  • 我在 SO 上向某人提供了一个实现,我也在我的项目中实现了该实现。它有不同的方法来刷新令牌。如果你愿意,我会在下面用我的答案链接给出答案。因此,如果它对您有帮助,其他用户也可以利用。

标签: javascript redux jwt refresh-token redux-middleware


【解决方案1】:

看来我已经通过像这样重写刷新中间件解决了这个问题:

function createRefreshMiddleware() {
  const postponedRSAAs = [];
  return ({ dispatch, getState }) => {
    const rsaaMiddleware = apiMiddleware({ dispatch, getState });
    return next => action => {
      if (isRSAA(action)) {
        try {
          const auth = JSON.parse(localStorage.getItem('auth'));
          const { refresh_token: refreshToken } = auth;
          const expirationTime = jwtDecode(auth.id_token).exp * 1000;
          const isAccessTokenExpiring =
            moment(expirationTime) - moment() < 300000;

          if (refreshToken && isAccessTokenExpiring) {
            postponedRSAAs.push(action);
            if (postponedRSAAs.length === 1) {
              return rsaaMiddleware(next)(
                dispatch(() => attemptTokenRefresh(refreshToken))
              ).then(() => {
                const postponedRSAA = postponedRSAAs.pop();
                return dispatch(postponedRSAA);
              });
            }
            return rsaaMiddleware(next)(action);
          }
          return rsaaMiddleware(next)(action);
        } catch (e) {
          console.log(e);
          return next(action);
        }
      }
      return next(action);
    };
  };
}

export default createRefreshMiddleware();

现在推迟的动作将始终与令牌刷新动作链接,因此我们不存在原始承诺以错误值解决的问题;而且更简洁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-14
    • 1970-01-01
    • 1970-01-01
    • 2019-12-14
    • 2018-11-26
    • 2021-07-14
    相关资源
    最近更新 更多