Apollo 客户端异步刷新令牌

Posted

技术标签:

【中文标题】Apollo 客户端异步刷新令牌【英文标题】:Apollo Client Async Refresh Token 【发布时间】:2020-08-27 08:49:11 【问题描述】:

当发生未经身份验证的错误时,我一直在努力异步刷新 Apollo 客户端中的令牌。 我已经查看了这方面的几个资源,例如 *** 答案、this Github 问题和this 博客文章。

主要是在获得新令牌之后,在重试失败的请求之前等待。看了上面博客中的cmets和Github issue中的cmets,好像很多人都成功解决了这个问题,但是我用新token拿到数据,retry完成后,表示重试是仍然使用旧令牌完成,所以它失败了。

这是执行刷新突变的函数。


export const getNewToken = (client) => 
  const refreshToken = getRefreshToken();
  return client.mutate(
    mutation: REFRESH_TOKEN,
    variables:  refreshToken ,
  );
;

这里是Auth Link,我对token做了一个console.log,来知道使用的是哪个token。

const authLink = setContext((_,  headers ) => 
  // get the authentication token from local storage if it exists
  const token = localStorage.getItem("token");
  console.log("Token in auth link: ", token);
  return 
    headers: 
      ...headers,
      authorization: token ? `JWT $token` : "",
    ,
  ;
);

然后在 Apollo 的 onError 函数中,我尝试重新创建上面链接博客中的第三个示例:

if (token && refreshToken) 
  return fromPromise(
    getNewToken(client)
      .then(( data:  refreshToken  ) => 
        console.log("Promise data: ", refreshToken);
        localStorage.setItem("token", refreshToken.token);
        localStorage.setItem("refreshToken", refreshToken.refreshToken);
        return refreshToken.token;
      )
      .catch((error) => 
        // Handle token refresh errors e.g clear stored tokens, redirect to login, ...
        console.log("Error after setting token: ", error);
        return;
      )
  )
    .filter((value) => 
      console.log("In filter: ", value);
      return Boolean(value);
    )
    .flatMap(() => 
      console.log("In flat map");
      // retry the request, returning the new observable
      return forward(operation);
    );

执行这个有两个问题: 1. 根本不调用filterflatMap 函数。 2. 在authLink 使用旧令牌记录呼叫后收到新令牌。这意味着forward(operation) 不会等待新令牌。

我还尝试了来自链接博客的并发请求。那里还有更多内容,所以这里是整个 src/index.js 的要点 https://gist.github.com/bzhr/531e1c25a4960fcd06ec06d8b21f143b

这里forward$.flatMap 根本不会被调用。和上面的例子一样的问题。

我不确定我的错误在哪里,因为很多人在博客上评论说它对他们有用。我已经多次检查我的代码。我需要一些帮助来调试它。主要是等待重试,直到新令牌准备好。

【问题讨论】:

【参考方案1】:

我也遇到了这个问题,但终于让它工作了。

    而不是 fromPromise。我使用了一个 util 方法,它使用 Observables 来订阅我们的 Promise .then 方法。
const _promiseToObservable = promiseFunc =>
  new Observable(subscriber => 
    promiseFunc.then(
      value => 
        if (subscriber.closed) return;
        subscriber.next(value);
        subscriber.complete();
      ,
      err => subscriber.error(err),
    );
    return subscriber; // this line can removed, as per next comment
  );

之后在 OnError 中使用此 util 方法而不是 fromPromise 调用您的 getNewToken() 方法。

    如果您使用 for GraphQlErrors,请删除 for 循环。取第一个数组元素graphQlErrors[0],它一般包含我们的错误数据。

进行这两项更改对我有用。

【讨论】:

缺少对此解决方案的引用github.com/apollographql/apollo-link/issues/…

以上是关于Apollo 客户端异步刷新令牌的主要内容,如果未能解决你的问题,请参考以下文章

使用 graphql 和 apollo 客户端刷新 Angular 令牌

使用 apollo-client + firebase auth 刷新令牌

如何使用 apollo Reactjs 客户端刷新 Firebase IdToken

如何在android中同步/限制某些异步http调用

每秒异步更新 UI,无需从服务器刷新页面

在 React 和 NodeJS 中未经授权重定向之前刷新令牌