3

我正在编写一个 Redux 中间件,它负责在用户点击redux-api-middlewareAPI_CALL之前将用户的 OAuth AccessToken 添加到阳离子。

// 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);
    }
}

但是,我也希望这个中间件检测用户的 AccesToken 何时过期......

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 流经我的中间件时寻找它们来做到这一点(该操作作为thunkAUTHENTICATION_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.
        }
    }
}

但是我对这种方法并不满意,因为不确定AUTHENTICATION_RESPONSEFSA 是否真的会命中减速器(它可能被其他中间件拦截,或者被进一步推迟)。

我考虑过的可能替代方法是让refreshAccessTokenactionCreator 返回一个返回 Promise 的 thunk;这样我的中间件可以在刷新和重放所有请求之前等待该承诺解决,即:

if (tokenExpired()) {
    // refreshAccessToken thunk returns a Promise. 
    dispatch(refreshAccessToken());
        .then(flushAndRedispatchDetainedActions();
}

或者,我可以让我的中间件直接观察商店并在auth.accessToken值发生变化时触发动作 - 但是,我不清楚中间件观察商店的指导是什么(我猜这是不可能的,因为中间件需要是在创建最终存储对象之前实例化。)

谢谢 :)

更新

在回家的路上思考问题;如果我要将实际的身份验证逻辑移出refreshAccessToken(一个 thunk'd 动作创建者),并移到中间件本身,那么我会省去很多痛苦:

// 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.
        }
    }
}
4

0 回答 0