【发布时间】:2019-08-04 02:03:27
【问题描述】:
我正在尝试找出一种方法将用户的身份验证状态存储在 redux 存储中。假设isAuthenticated 存储用户是否登录的状态。现在,我有一个由服务器发送的 cookie(httpOnly),它会记住用户,这样他们就不需要在每次访问应用程序时都输入凭据。
流程:用户某天登录到应用程序但没有注销并关闭浏览器。现在,他回来访问我的应用程序。由于 cookie 存在于浏览器中,这将由应用程序自动发送(无需用户交互),如果 cookie 有效,isAuthenticated: true。非常简单的需求。
跟踪身份验证状态应该是应用程序完成的第一件事,所以我把这个逻辑放在最前面,在 App.js 呈现之前。
class App extends Component {
store = configureStore();
render() {
return (
<Provider store={this.store}>
<ConnectedRouter history={history}>
<>
<GlobalStyle />
<SiteHeader />
<ErrorWrapper />
<Switch>
<PrivateHomeRoute exact path="/" component={Home} />
<Route exact path="/login" component={LoginPage} />
<PrivateHomeRoute path="/home" component={Home} />
........code
}
这是configureStore()
export const history = createBrowserHistory();
const configureStore = () => {
const sagaMiddleware = createSagaMiddleware();
const store = createStore(
rootReducer(history),
composeEnhancers(applyMiddleware(sagaMiddleware, routerMiddleware(history)))
);
sagaMiddleware.run(rootSaga);
store.dispatch({ type: AUTH.AUTO_LOGIN });
return store;
};
store.dispatch({ type: AUTH.AUTO_LOGIN }); 是我尝试应用程序执行自动登录作为应用程序中的第一个操作的代码。此操作由redux-saga 处理
function* handleAutoLogin() {
try {
const response = yield call(autoLoginApi);
if (response && response.status === 200) {
yield put(setAuthenticationStatus(true));
}
} catch (error) {
yield put(setAuthenticationStatus(false));
}
}
function* watchAuthLogin() {
yield takeLatest(AUTH.AUTO_LOGIN, handleAutoLogin);
}
autoLoginApi 是对服务器的axios 调用,它将携带cookie。 setAuthenticationStatus(true) 是动作创建者,它将 isAuthenticated 设置为 true false。
所以,是的,这但没有按预期工作。因为,应用程序应该首先设置isAuthenticated,然后继续使用 App.js 的 render()。但是,由于设置isAuthenticated 需要一些时间(api 调用),因此应用程序首先使用isAuthenticated: false 进行渲染,然后在完成AUTH.AUTO_LOGIN 之后,应用程序会为经过身份验证的用户重新渲染。
那有什么问题呢?对于普通组件可能不是问题,例如这个SiteHeader组件
class SiteHeader extends React.Component {
render() {
const { isLoggedIn } = this.props;
if (isLoggedIn === null) {
return "";
} else {
if (isLoggedIn) {
return (
<LoggedInSiteHeader />
);
} else {
return (
<LoggedOutSiteHeader />
);
}
}
}
}
const mapStateToProps = ({ auth, user }) => ({
isLoggedIn: auth.isLoggedIn,
});
export default connect(
mapStateToProps,
null
)(SiteHeader);
但是,此解决方案不适用于自定义路由。
const PrivateHomeRoute = ({ component: ComponentToRender, ...rest }) => (
<Route
{...rest}
render={props =>
props.isLoggedIn ? (
<ComponentToRender {...props} />
) : (
<Redirect to="/login" />
)
}
/>
);
const mapStateToProps = auth => ({
isLoggedin: auth.isLoggedIn
});
export default connect(
mapStateToProps,
null
)(PrivateHomeRoute);
PrivateHomeRoute 在 redux 存储更新之前得到解决,因此路由总是转到"/login"。
我正在寻找一种解决方案,在该解决方案中,应用程序在身份验证操作未完成之前不会继续进行。但是,我不知道该把代码放在什么地方以及放在哪里?
我尝试了几件事:
-
async awaitonconfigureStore()- 错误来了 -
async await上App.js- 错误
PS:我正在使用的库 redux、redux-saga、react-router-dom、connected-react-router、axios
【问题讨论】:
-
也许这个答案会为您提供类似的解决方案? stackoverflow.com/questions/31723095/…
标签: reactjs redux react-redux redux-saga connected-react-router