当多个API的Access token同时失效时,如何刷新并行调用的多个API的Access token?

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

在我的 React Native 应用程序中,登录后我会获得访问令牌和刷新令牌。

有一个常用函数,当访问令牌无效时,使用刷新令牌再次调用访问令牌

在我的主页上,有6个API,但是当访问令牌失效时,这6个API并行调用公共函数并刷新访问令牌。这使得该特定用户被阻止。

如何预防这种情况?当第一个 API 的令牌失效时,使用标志阻止其余 API 是不可行的,因为在第一个响应之前,所有 API 都将刷新访问令牌。

首先触发

handleResponse
函数,然后代码到达
getNewToken
函数,然后到达
dispatch(logout());
,因为对accesstoken的调用没有成功,并且由于多次调用注销而导致应用程序崩溃。

const handleResponse = async (
        res: ApiResponse<BaseResponseProp, BaseResponseProp> | null,
      ) => {
     
          if (res?.data?.error === 'invalid_token') {
            let tokenVal;
            try {
              if (token.refresh_token) {
                tokenVal = await getNewToken(token.refresh_token);
              } else {
                //refresh the public token
                tokenVal = await refreshPublicToken();
              }
              if (tokenVal?.access_token && tokenVal?.access_token.length > 0) {
                const newTokenHeader = {
                  Authorization: `Bearer ${tokenVal.access_token}`,
                };
                invoke({
                  requestHeader: { ...requestHeader, ...newTokenHeader },
                  requestBody,
                  requestParams,
                  requestQuery,
                  url: formattedEndpoint,
                  onResultCallback,
                  onErrorCallback,
                });
                dispatch(setToken(tokenVal));
              } else {
                setInvalidToken(true);
                navigation.dispatch(
                  StackActions.replace(NAVIGATION_SCREENS.ROOT),
                );
                return;
              }
              return;
            } catch (e) {
              const newToken = await refreshPublicToken();
              dispatch(setToken(newToken));
              return;
            }
          }
          const err = new CustomError(
            res?.data?.error || res?.originalError?.message,
            res?.data?.status || 200,
          );
          if (typeof onErrorCallback === 'function') {
            onErrorCallback(err);
          } else if (typeof onError === 'function') {
            onError(err as CustomError);
          }
          handleParseError(err);
        } else {
          const responseData = res?.data as unknown as R;
          if (renderData) {
            setData(res?.data);
          }
          if (typeof onResultCallback === 'function') {
            onResultCallback(res?.data as unknown as R);
          } else if (typeof onResult === 'function') {
            onResult(res?.data);
          }
        }
      };

 const getNewToken = async (refToken: string) => {
    let formattedEndpoint = ENDPOINT.LOGIN;
    let tokenVal = {};
    const header = { refresh_token: refToken };
    const requestQuery = {
      ...REFRESH_AUTH_HEADERS,
      ...header,
    };
    const queryParams = new URLSearchParams({
      ...requestQuery,
    }).toString();
    formattedEndpoint = `${formattedEndpoint}?${queryParams}`;
    const refreshResponse = await api.post<LoginSuccess>(
      formattedEndpoint,
      {},
      {
        headers: basicAuthHeaders,
      },
    );
    if (refreshResponse.status === 200) {
      tokenVal = {
        access_token: refreshResponse.data?.access_token,
        refresh_token: refreshResponse.data?.refresh_token,
        expires_in: refreshResponse.data?.expires_in,
        type: 'private',
      };
    } else {
      // The logout gets called multiple times and app crashes
      dispatch(logout());
      tokenVal = {
        access_token: null,
        token_type: null,
        refresh_token: null,
        expires_in: null,
        scope: null,
        id_token: null,
        type: 'public',
      };
      tokenVal = await refreshPublicToken();
      navigation.dispatch(StackActions.replace(NAVIGATION_SCREENS.ROOT));
    }
    return tokenVal;
  };
android ios react-native access-token refresh-token
1个回答
0
投票

在 OAuth 架构中发出并发 API 请求时,需要使用 2 种同步技术:

  • 同步令牌刷新
  • 同步会话过期和用户重新身份验证

对于第一个,请考虑使用这样的代码对承诺集合进行排队,并且仅对第一个进行令牌刷新。然后为每个 API 请求返回相同的刷新结果并允许它们恢复:

await this._concurrencyHandler.execute(this._performTokenRefresh);

要处理会话过期,请等待所有 API 请求完成,然后查看是否有任何令牌刷新请求失败并出现

invalid_grant
错误代码。如果其中至少有一个这样做,则重新运行登录流程,并且仅执行一次。我的示例使用此代码来实现这一点。

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