redux-api-middlewareに到達する前に、ユーザーの OAuth AccessToken をAPI_CALL
陽イオンに追加する責任がある Redux Middleware を作成しています。
// sign appends the `Authorization` HTTP Header to an API_CALL action
function sign(action) {
action[CALL_API].headers = {
...action[CALL_API].headers,
Authorization: `Bearer ${getState()auth.accessToken}`;
}
}
// Redux middleware signature.
return ({dispatch, getState}) => {
return next => action => {
if (action[CALL_API]) {
sign(action);
}
return next(action);
}
}
ただし、ユーザーの AccessToken の有効期限が切れたことをこのミドルウェアで検出することも必要です...
function tokenExpired() {
return (Date.now() > getState().auth.expirationTime);
}
これが発生すると、ミドルウェアはアクションを保留し (next
チェーン内のミドルウェアに渡されないようにします)、内部リストに格納します。次に、非同期を開始します。「リフレッシュ アクセス トークン」FSA のディスパッチによるトークン リフレッシュ プロセス:
if (tokenExpired()) {
// detainActions is an array, declared outside
// of the middleware's scope.
detainActions.push(action);
dispatch(refreshAccessToken());
}
else {
next(sign(action));
}
最後に、「アクセス トークンの更新」フローがいつ完了したかをリッスンし、保留中のすべてのアクションをフラッシュ (再ディスパッチ) したいと考えています。AUTHENTICATION_RESPONSE
現在、 FSA が私のミドルウェアを流れるときに、FSAを監視することでこれを行っています(アクションは、サンクAUTHENTICATION_RESPONSE
の副作用としてディスパッチされます)。refreshAccessToken
// Redux middleware signature.
return ({dispatch, getState}) => {
return next => action => {
if (action.type === AUTHENTICATION_RESPONSE && !action.error) {
// Let the AuthResponse action pass to the store.
next(action);
// Flush detained actions now we have a new grant.
return flushAndRedispatchDetainedActions(dispatch);
}
else {
// Sign CALL_API requests logic as above.
}
}
}
ただし、FSA が実際にレデューサーをヒットするという確実性がないため、このアプローチには満足していませんAUTHENTICATION_RESPONSE
(他のミドルウェアによって傍受されるか、さらに延期される可能性があります)。
私が検討した可能な代替アプローチは、refreshAccessToken
actionCreator に Promise を返すサンクを返させることです。そうすれば、ミドルウェアはすべてのリクエストをフラッシュして再生する前に、その約束が解決するのを待つことができます。
if (tokenExpired()) {
// refreshAccessToken thunk returns a Promise.
dispatch(refreshAccessToken());
.then(flushAndRedispatchDetainedActions();
}
または、ミドルウェアでストアを直接監視し、値が変更されたときにアクションをトリガーすることもできますが、ミドルウェアがストアを監視するためauth.accessToken
のガイダンスが何であるかは明確ではありません (ミドルウェアが必要なため、不可能だと思います)最終的なストア オブジェクトが作成される前にインスタンス化されます)。
ありがとう :)
アップデート
帰り道に問題を考える。実際の認証ロジックをrefreshAccessToken
(サンクされたアクション クリエーター) からミドルウェア自体に移動すると、多くの手間が省けます。
// Redux middleware signature.
return ({dispatch, getState}) => {
return next => action => {
if (action[CALL_AUTH]) {
authHelper.refreshGrant()
.then(grant => dispatch(processGrant(newGrant));
}
else {
// Sign CALL_API requests logic as above.
}
}
}