Znalazłem sposób na rozwiązanie tego problemu. Nie jestem pewien, czy jest to podejście oparte na najlepszych praktykach i prawdopodobnie istnieją pewne ulepszenia, które można w nim wprowadzić.
Mój oryginalny pomysł pozostaje: odświeżanie JWT jest w oprogramowaniu pośredniczącym. To oprogramowanie pośrednie musi nadejść przed thunk
, jeśli użyto thunk
.
...
const createStoreWithMiddleware = applyMiddleware(jwt, thunk)(createStore);
Następnie w kodzie oprogramowania pośredniego sprawdzamy, czy token wygasł przed jakąkolwiek operacją asynchroniczną. Jeśli wygasł, sprawdzamy również, czy już odświeżamy token - aby mieć taki czek, dodajemy obietnicę nowego tokena do stanu.
import { refreshToken } from '../actions/auth';
export function jwt({ dispatch, getState }) {
return (next) => (action) => {
// only worry about expiring token for async actions
if (typeof action === 'function') {
if (getState().auth && getState().auth.token) {
// decode jwt so that we know if and when it expires
var tokenExpiration = jwtDecode(getState().auth.token).<your field for expiration>;
if (tokenExpiration && (moment(tokenExpiration) - moment(Date.now()) < 5000)) {
// make sure we are not already refreshing the token
if (!getState().auth.freshTokenPromise) {
return refreshToken().then(() => next(action));
} else {
return getState().auth.freshTokenPromise.then(() => next(action));
}
}
}
}
return next(action);
};
}
Najważniejszą częścią jest funkcja refreshToken
. Ta funkcja musi wysłać akcję, gdy token jest odświeżany, aby państwo zawierało obietnicę nowego tokena. W ten sposób, jeśli wyślemy wiele akcji asynchronicznych, które używają tokenu uwierzytelniania jednocześnie token zostanie odświeżony tylko raz.
export function refreshToken(dispatch) {
var freshTokenPromise = fetchJWTToken()
.then(t => {
dispatch({
type: DONE_REFRESHING_TOKEN
});
dispatch(saveAppToken(t.token));
return t.token ? Promise.resolve(t.token) : Promise.reject({
message: 'could not refresh token'
});
})
.catch(e => {
console.log('error refreshing token', e);
dispatch({
type: DONE_REFRESHING_TOKEN
});
return Promise.reject(e);
});
dispatch({
type: REFRESHING_TOKEN,
// we want to keep track of token promise in the state so that we don't try to refresh
// the token again while refreshing is in process
freshTokenPromise
});
return freshTokenPromise;
}
Zdaję sobie sprawę, że jest to dość skomplikowane. Jestem również trochę zaniepokojony wysyłaniem akcji w refreshToken
, która nie jest sama w sobie. Daj mi znać o każdym innym podejściu, które wiesz, że obsługuje wygasanie tokena JWT za pomocą redux.
Proponuję, abyś spojrzał na bibliotekę zwaną [redux-saga] (https://github.com/yelouafi/redux-saga) ... To rozwiązuje ten problem doskonale . –