如何在不破坏异步流的情况下自动刷新redux中的JWT?

问题描述 投票:4回答:1

High-level description

我有一个使用Google Oauth的React / redux /电子应用程序。我希望能够在到期时自动刷新访问令牌。我已经研究过这个并使用中间件半成功地解决了它,但我的解决方案在某些情况下是错误的。

我已经实现了一个在每个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变量被分配给正确Promise的已解析值?

Links to Project Code

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

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响应令牌刷新。

javascript redux jwt refresh-token redux-middleware
1个回答
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();

现在,推迟的操作将始终与令牌刷新操作相关联,因此我们没有原始承诺解决错误值的问题;加上它更简洁。

© www.soinside.com 2019 - 2024. All rights reserved.