2017-10-15 6 views
0

次のアクションが実行される前にリフレッシュトークンに移動し、アクセストークンの有効期限が切れたときに他のアクションを実行できるミドルウェアがあります。redux refreshトークンミドルウェア

一度に複数のリクエストを行い、アクセストークンが終了した場合、私は要求しているのと同じくらいリフレッシュトークンを取得しようとしています。これを防ぐためにstateのisLoadingプロパティをチェックしています。しかし、要求の後、isLoading値は減速機で真です、それはミドルウェアでは間違っているようですので、何度も何度もリクエストします。

fetching_refresh_tokenアクションでrefreshTokenPromiseを送信していますが、state.refreshTokenPromiseを取得することはありません。常に定義されていません。

私は間違いなく状態に問題があります。

ここで私の質問ですが、どのようにミドルウェアの状態値の変化にアクセスできますか?

更新トークンミドルウェア:(このバージョンは、エンドポイントを複数回ヒット)

import { AsyncStorage } from 'react-native'; 
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv'; 
import moment from 'moment'; 
import Api from '../lib/api'; 
import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

export default function tokenMiddleware({ dispatch, getState }) { 
    return next => async (action) => { 
    if (typeof action === 'function') { 
     const state = getState(); 
     if (state) { 
     const expiresIn = await AsyncStorage.getItem('EXPIRES_IN'); 
     if (expiresIn && isExpired(JSON.parse(expiresIn))) { 
      if (!state.refreshToken.isLoading) { 
      return refreshToken(dispatch).then(() => next(action)); 
      } 
      return state.refreshTokenPromise.then(() => next(action)); 
     } 
     } 
    } 
    return next(action); 
    }; 
} 

async function refreshToken(dispatch) { 
    const clientId = await AsyncStorage.getItem('CLIENT_ID'); 
    const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET'); 
    const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN'); 

    const userObject = { 
    grant_type: 'refresh_token', 
    client_id: JSON.parse(clientId), 
    client_secret: JSON.parse(clientSecret), 
    refresh_token: refreshToken1, 
    }; 

    const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&'); 

    const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => { 
    await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token); 
    await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token); 
    await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires'])); 

    dispatch({ 
     type: FETCHING_REFRESH_TOKEN_SUCCESS, 
     data: res, 
    }); 

    return res ? Promise.resolve(res) : Promise.reject({ 
     message: 'could not refresh token', 
    }); 
    }).catch((err) => { 
    dispatch({ 
     type: FETCHING_REFRESH_TOKEN_FAILURE, 
    }); 

    throw err; 
    }); 

    dispatch({ 
    type: FETCHING_REFRESH_TOKEN, 
    refreshTokenPromise, 
    }); 

    return refreshTokenPromise; 
} 

function isExpired(expiresIn) { 
    return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN; 
} 

トークン減速更新:ところで

import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

const initialState = { 
    token: [], 
    isLoading: false, 
    error: false, 
}; 

export default function refreshTokenReducer(state = initialState, action) { 
    switch (action.type) { 
    case FETCHING_REFRESH_TOKEN: 
     return { 
     ...state, 
     token: [], 
     isLoading: true, 
     }; 
    case FETCHING_REFRESH_TOKEN_SUCCESS: 
     return { 
     ...state, 
     isLoading: false, 
     token: action.data, 
     }; 
    case FETCHING_REFRESH_TOKEN_FAILURE: 
     return { 
     ...state, 
     isLoading: false, 
     error: true, 
     }; 
    default: 
     return state; 
    } 
} 

、私はgetStateをrefreshTokenへの機能に送信し、私はrefreshTokenの状態値が変化することに気づきます。しかし、このバージョンでは、リフレッシュトークンはリフレッシュされずに他のアクションに移動します。

モンキーパッチを当てたバージョン:(このバージョンは1つのだけ要求を行う)

import { AsyncStorage } from 'react-native'; 
import { MIN_TOKEN_LIFESPAN } from 'react-native-dotenv'; 
import moment from 'moment'; 
import Api from '../lib/api'; 
import { 
    FETCHING_REFRESH_TOKEN, 
    FETCHING_REFRESH_TOKEN_SUCCESS, 
    FETCHING_REFRESH_TOKEN_FAILURE } from '../actions/constants'; 

export default function tokenMiddleware({ dispatch, getState }) { 
    return next => async (action) => { 
    if (typeof action === 'function') { 
     const state = getState(); 
     if (state) { 
     const expiresIn = await AsyncStorage.getItem('EXPIRES_IN'); 
     if (expiresIn && isExpired(JSON.parse(expiresIn))) { 
      if (!state.refreshTokenPromise) { 
      return refreshToken(dispatch, getState).then(() => next(action)); 
      } 
      return state.refreshTokenPromise.then(() => next(action)); 
     } 
     } 
    } 
    return next(action); 
    }; 
} 

async function refreshToken(dispatch, getState) { 
    const clientId = await AsyncStorage.getItem('CLIENT_ID'); 
    const clientSecret = await AsyncStorage.getItem('CLIENT_SECRET'); 
    const refreshToken1 = await AsyncStorage.getItem('REFRESH_TOKEN'); 

    const userObject = { 
    grant_type: 'refresh_token', 
    client_id: JSON.parse(clientId), 
    client_secret: JSON.parse(clientSecret), 
    refresh_token: refreshToken1, 
    }; 

    if (!getState().refreshToken.isLoading) { 
    const userParams = Object.keys(userObject).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(userObject[key])).join('&'); 

    const refreshTokenPromise = Api.post('/token', userParams).then(async (res) => { 
     await AsyncStorage.setItem('ACCESS_TOKEN', res.access_token); 
     await AsyncStorage.setItem('REFRESH_TOKEN', res.refresh_token); 
     await AsyncStorage.setItem('EXPIRES_IN', JSON.stringify(res['.expires'])); 

     dispatch({ 
     type: FETCHING_REFRESH_TOKEN_SUCCESS, 
     data: res, 
     }); 

     return res ? Promise.resolve(res) : Promise.reject({ 
     message: 'could not refresh token', 
     }); 
    }).catch((err) => { 
     dispatch({ 
     type: FETCHING_REFRESH_TOKEN_FAILURE, 
     }); 

     throw err; 
    }); 

    dispatch({ 
     type: FETCHING_REFRESH_TOKEN, 
     refreshTokenPromise, 
    }); 

    return refreshTokenPromise; 
    } 
} 

function isExpired(expiresIn) { 
    return moment(expiresIn).diff(moment(), 'seconds') < MIN_TOKEN_LIFESPAN; 
} 

ありがとうございました。あなたはReduxの-サガ

https://github.com/redux-saga/redux-saga

Reduxの-サガから利益を得ることができる

+0

ミドルウェアのisLoading値を確認している場所が表示されません。 – Freez

+0

私は他のものを試してみました。 ? – ccoeder

+0

イム好奇心が – Freez

答えて

0

は、あなたの行動を監視し、いくつかの特定のアクションが満たされたときに反応することができるだけで背景ランナーです。あなたはすべてのアクションのために耳を傾け、すべてに反応したり

https://redux-saga.js.org/docs/api/#takelatestpattern-saga-args

しばらくの再来-サンクは、外出先でアクションを作成し、いくつかの私を待つだけで、別の方法であるコメントで述べたようにあなただけの最新のものに反応することができ/ Oを実行してから、I/Oが完了したらさらにいくつかのアクションを作成します。これは同期されたコードパターンによく似ていて、redux-sagasはマルチスレッドに似ています。メインスレッドでは、あなたのアプリケーションを実行しているバックグラウンドスレッドで、あなたはサガのモニターと反応を持っています