【问题标题】:Prevent Multiple Token Refreshes With API React Hook使用 API React Hook 防止多次令牌刷新
【发布时间】:2020-06-23 16:46:26
【问题描述】:

我有一个名为 useAPICall 的 API 挂钩,它有一个回调 call。此回调检查存储在名为 auth 的 reactn 变量中的令牌是否已过期,如有必要刷新它,然后调用 fetch 函数。

我在我的组件中这样称呼它:

const [api] = useAPICall();

useEffect(() => {
    api.call('/api/settings/mine/').then(data => {
        // do stuff here
    });
}, []);

它确实有效。它通过身份验证流程并调用 API。但是如果我有 useAPICall 是多个组件都尝试在同一时间调用 API(例如冷页面加载),那么它的每个实例都会调用刷新令牌方法,因为它已过期。

身份验证信息(访问/刷新令牌)存储在 reactn 全局变量 auth 中,如下所示,在 useAPICall.js 挂钩内

import React, {useCallback, useContext, useEffect, useMemo, useState} from 'react';
import {useDispatch, useGlobal} from 'reactn';


export function useAPICall() {
    const [auth, setAuth] = useGlobal('auth');
    const authRefreshSuccess = useDispatch('authRefreshSuccess');

    async function refreshToken() {
        console.log('Refreshing access token...');
        const authResponse = await fetch('/api/auth/token/refresh/', {
            method: 'POST',
            credentials: 'same-origin',
            body: JSON.stringify({refresh: auth.refresh.token}),
            headers: {
                'Content-Type': 'application/json',
            },
        });
        if (authResponse.ok) {
            const authToken = await authResponse.json();
            await authRefreshSuccess(authToken);
            return authToken.access;
        }
    }

    function isTokenExpired() {
        if (localAuth.access)
            return auth.access.exp <= Math.floor(Date.now() / 1000);
        else
            return false;
    }

    const call = useCallback(async (endpoint, options={headers: {}}) => {
        console.log('performing api call');
        token = undefined;

        if (isTokenExpired())
            token = await refreshToken();
        else
            token = localAuth.access.token;

        const res = await fetch(endpoint, {
            ...options,
            headers: {
                ...options.headers,
                'Authorization': `Bearer ${token}`,
            }
        });
        if (!res.ok)
            throw await res.json();
        return res.json();

    }, []);

    const anonCall = useCallback(async (endpoint, options={}}) => {
        const res = await fetch(endpoint, options);
        if (!res.ok)
            throw await res.json();
        return res.json();

    }, []);


    const api = useMemo(
        () => ({
            call,
            anonCall,
        }),
        [call, anonCall,]
    );

    return [api]
}

如何防止他们多次触发刷新方法?

如果有更好的方法(不使用 redux)来获得通用 API 流(任何 API 调用都会首先检查访问令牌并在必要时刷新),那么我愿意倾听。

【问题讨论】:

    标签: reactjs jwt


    【解决方案1】:

    我设法通过在全局变量中存储一个承诺来做到这一点。

    let refreshPromise = null;
        
    export function useAuthentication() {
        
          async function getBearer() {
        
            if (isExpired(jwt)) {
              if (refreshPromise == null) {
                refreshPromise = refresh().then((jwt) => {
                  refreshPromise = null;
                  return jwt;
                });
              }
              await refreshPromise;
            }
        
            let authData = getAuthData();
            if (authData && authData.accessToken) {
              return `Bearer ${authData.accessToken}`;
            }
            return null;
          }
        
          const AuthenticationService = {
            getBearer,
            ...
          };
        
         return AuthenticationService;
    }
    

    希望这会有所帮助!

    【讨论】:

      猜你喜欢
      • 2020-10-13
      • 2022-10-31
      • 2021-01-24
      • 1970-01-01
      • 2020-01-26
      • 2019-11-26
      • 1970-01-01
      • 1970-01-01
      • 2015-05-22
      相关资源
      最近更新 更多