【问题标题】:Way to handle refresh token处理刷新令牌的方法
【发布时间】:2020-01-31 10:49:50
【问题描述】:

我正在开发登录功能,刷新令牌时遇到问题。

当令牌过期请求刷新令牌时,删除旧令牌,并将新令牌保存到 AsyncStorage。

登录成功后必须使用函数 A 和 B。函数 A 正在使用新令牌发出请求。函数 B 说它需要刷新令牌,所以请求刷新令牌(请求成功,令牌正在刷新)但是请求 A 现在使用的令牌invalid - 我认为这是由于异步而发生的

这是我用来刷新令牌的代码:

axiosInstance.interceptors.response.use(
  function (response) {
    return response;
  },
  async function (error) {
    if (error.response.status === CODE_TOKEN_EXPIRED) {
      try {
        const token = await authenticationService.getRefreshToken();
        const response = await authenticationService.refreshToken(token);
        await authenticationService.removeToken();
        await authenticationService.storeToken(response.data.params.access_token);
        await authenticationService.storeRefreshToken(response.data.params.refresh_token);
        error.config.headers.Authorization = 'Bearer ' + response.data.params.access_token;
        error.response.config.headers['Authorization'] = 'Bearer ' + response.data.params.access_token;
        return axiosInstance(error.config);
      } catch (err) {
        console.log(2, err);
        await authenticationService.removeToken();
        navigationService.navigate('LoginForm');
      }
    }
    return Promise.reject(error);
  }
);

有人知道如何处理刷新令牌的异步调用吗?

【问题讨论】:

    标签: javascript react-native axios


    【解决方案1】:

    首先是让您检查是否将令牌更改为正确的 axios 实例。有必要像您一样更改 error.response 配置上的 Authorization 标头,但对于主 axios 实例(如果有的话)也是如此:axios.defaults.headers.common["Authorization"] = "Bearer " + access_token;

    如果是多个并行请求,可能需要在刷新令牌后推迟问题和答案变得复杂,但请使用 axios 使用完整的刷新逻辑检查此gist

    【讨论】:

      【解决方案2】:

      我在 fetch API 中实现了相同的场景。你也可以在 axios API 中做同样的事情。试试这个来避免拦截器的概念。

      Api.ts

      export const api = ({ method, url, body, isProtected = true }) => {
        return new Promise((resolve, reject) => {
          const payload = {
            method,
            headers: {
              Accept: 'application/json',
              'Content-Type': 'application/json'
            }
          };
          if (body !== null) {
            (payload as any).body = JSON.stringify(body);
          }
      
              /**
              * "isProtected" is used for API call without authToken
              */
      
          if (isProtected) {
            AsyncStorage.getItem(ACCESS_TOKEN).then(accessKey => {
              (payload.headers as any).Authorization = `Bearer ${accessKey}`;
              fetch(url, payload)
                .then((response: any) => {
      
                              /*
                              * 419 status denotes the timeout of authToken
                              */
      
                  if (response.status == 419) {
                    // refresh token
                    AsyncStorage.getItem(REFRESH_TOKEN).then(refreshKey => {
      
                      const payloadRef = {
                        method: 'POST',
                        headers: {
                          Accept: 'application/json',
                          'Content-Type': 'application/json',
                          Authorization: 'Bearer ' + refreshKey
                        }
                      };
                                      /*
                                      * This call refresh the authToken using refreshing call to renew the authToken
                                      */
                      fetch(URL.baseUrl + "/refresh", payloadRef)
                        .then((response: any) => response.json())
                        .then(response => {
      
                                              /*
                                              * if refresh token expired. redirect to login page
                                              */
      
                          if (response.status !== codes.SUCCESS) {
                            if (!User.sessionOver) {
                              User.sessionOver = true;
                              Alert.alert(
                                'Alert',
                                'Session Timeout',
                                [
                                  {
                                    text: 'Get back to Login',
                                    onPress: () => {
                                      // get to Login page
                                    }
                                  }
                                ],
                                { cancelable: false }
                              );
                            }
                          } else if (response.status == codes.SUCCESS) {
      
                                                  /*
                                                  * If refresh token got refreshed and set it as authToken and retry the api call.
                                                  */
      
                            AsyncStorage.setItem(ACCESS_TOKEN, response.payload.access_key).then(() => {
                              (payload.headers as any).Authorization = 'Bearer ' + response.payload.access_key;
                              fetch(url, payload)
                                .then(response => response.json())
                                .then(response => {
                                  if (response.status == codes.SUCCESS) {
                                    resolve(response);
                                  }
                                })
                                .catch(error => {
                                  reject(error);
                                });
                            });
                          }
                        });
                    });
                  } else {
                    resolve(response.json());
                  }
                })
                .catch(error => {
                  reject(error);
                });
            });
          } else {
            fetch(url, payload)
              .then((response: any) => {
                response = response.json();
                resolve(response);
              })
              .catch(error => {
                reject(error);
              });
          }
        });
      };
      

      MovieService.ts

      import { api } from '../services/api';
      import { URL } from '../config/UrlConfig';
      
      const getMovies = () => {
        const method = 'GET';
        const url = URL.baseUrl + '/v1/top/movies';
        const body = null;
        const isProtected = true;
        return api({ method, url, body, isProtected });
      };
      
      export { getMovies };
      

      【讨论】:

        【解决方案3】:

        也许会有所帮助 - https://gist.github.com/ModPhoenix/f1070f1696faeae52edf6ee616d0c1eb

        import axios from "axios";
        import { settings } from "../settings";
        import { authAPI } from ".";
        
        const request = axios.create({
          baseURL: settings.apiV1,
        });
        
        request.interceptors.request.use(
          (config) => {
            // Get token and add it to header "Authorization"
            const token = authAPI.getAccessToken();
            if (token) {
              config.headers.Authorization = token;
            }
        
            return config;
          },
          (error) => Promise.reject(error)
        );
        
        let loop = 0;
        let isRefreshing = false;
        let subscribers = [];
        
        function subscribeTokenRefresh(cb) {
          subscribers.push(cb);
        }
        
        function onRrefreshed(token) {
          subscribers.map((cb) => cb(token));
        }
        
        request.interceptors.response.use(undefined, (err) => {
          const {
            config,
            response: { status },
          } = err;
          const originalRequest = config;
        
          if (status === 401 && loop < 1) {
            loop++;
            if (!isRefreshing) {
              isRefreshing = true;
              authAPI.refreshToken().then((respaonse) => {
                const { data } = respaonse;
                isRefreshing = false;
                onRrefreshed(data.access_token);
                authAPI.setAccessToken(data.access_token);
                authAPI.setRefreshToken(data.refresh_token);
                subscribers = [];
              });
            }
        
            return new Promise((resolve) => {
              subscribeTokenRefresh((token) => {
                originalRequest.headers.Authorization = `Bearer ${token}`;
                resolve(axios(originalRequest));
              });
            });
          }
          return Promise.reject(err);
        });
        
        export default request;
        
        

        【讨论】:

          猜你喜欢
          • 2014-08-01
          • 2014-06-15
          • 2017-07-18
          • 1970-01-01
          • 1970-01-01
          • 2019-09-05
          • 2020-01-22
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多