Я пытаюсь найти способ сохранить состояние аутентификации пользователя в хранилище 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
разрешается до того, как обновляется резервное хранилище, следовательно, Маршрут всегда идет к "/login"
.
Я ищу решение, в котором приложение не будет работать до тех пор, пока действие аутентификации не завершится.Но я понятия не имею, что и куда помещать этот код?
Несколько вещей, которые я пробовал:
async await
на configureStore()
- Ошибка пришла async await
on App.js
- Ошибка
PS: библиотеки, которые я использую: redux, redux-saga, response-router-dom, connected-response-router, axios