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

高级描述

我有一个使用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将是未定义的,因为调度似乎使用令牌刷新操作的值而不是fetchThreads操作来解析.

如何确保令牌被刷新(并在状态/ localStorage中更新),fetchThreads被更新的令牌调度,并且线程变量被分配给正确的Promise的已解析值?

项目代码的链接

0700年,它受到了this article的启发.

This is the token refresh action creator.

This is the line in my queryThreads action creator在令牌必须刷新时抛出(threads.payload未定义).

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

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

最佳答案 看起来我已经通过重写刷新中间件解决了这个问题,如下所示:

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();

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

点赞