我正在编写一个小型待办事项应用程序,在根据后端数据重新路由用户时遇到问题。该应用程序正在使用:
express-session
创建服务器端用户会话connect-mongodb-session
存储会话数据- 用于应用程序状态管理的
react-redux
当用户登录时,名为isLoggedIn
的User
模型属性将设置为true
。该值用于将用户重定向到LandingPage
组件,在那里他们可以创建新的待办事项。这很好,但问题是,如果刷新登录页,则在LandingPage
呈现之前,isLoggedIn
的值尚未从后端到达。这会导致用户被重新路由到登录页面,然后数据到达,然后他们再次被重新路由至登录页面。
登录页面"闪烁"是非常烦人的,我找不到任何方法来绕过它。我试着在localStorage
中存储一个布尔值isLoggedIn
,效果很好,但这肯定不能解决使用服务器端会话的问题?
以下是我的代码片段,谢谢
App.js
import { getUser } from "./redux/actions/auth";
const App = withRouter(({ user, data }) => {
useEffect(() => {
store.dispatch(getUser()); // user data loaded every time app re-renders
}, []);
return (
<Provider store={store}>
<Router>
<div className='my-app'>
<Switch>
<Route exact path='/login' component={Login} />
<Private
isLoggedIn={isLoggedIn}
path='/landing'
component={LandingPage}
/>
</Switch>
</div>
</Router>
</Provider>
);
const Private = ({ isLoggedIn, component: Component, ...rest }) => {
return (
<Route
{...rest}
render={props =>
isLoggedIn ? (
<Component {...props} />
) : (
// I think the problem is here - because isLoggedIn is not available from the backend
// call yet, so login page gets rendered before the data arrives
<Redirect to='/login' {...props} />
)
}
/>
);
};
Login.js
render() {
const { user } = this.props;
if (user.isLoggedIn) return <Redirect to='/landing' />; // user sent to landing if they are logged in
return (... login form jsx)
}
Login.propTypes = {
user: PropTypes.object
};
const mapStateToProps = state => ({
user: state.auth.user
});
export default connect(mapStateToProps)(Login);
getUser.js
export const getUser = () => async dispatch => {
try {
const response = await axios.get("/api/user");
dispatch({
type: LOADED_USER,
payload: response.data
});
} catch (error) {
dispatch({
type: LOAD_USER_FAILED
});
}
};
getUserReducer.js
const initialState = {
user: {}
};
export default function(state = initialState, action) {
const { type, payload } = action;
switch (type) {
case LOGIN_SUCCEEDED:
case LOADED_USER:
return {
...state,
user: payload
};
case LOGIN_FAILED:
case LOAD_USER_FAILED:
return {
...state,
user: {}
};
default:
return state;
}
}
所以有几种方法可以做到这一点。一种方法是创建一个经过身份验证的路由,其唯一目的是验证会话cookie,例如/me
。
如果用户以前登录过,则浏览器应具有作为cookie的有效会话。这意味着CCD_ 13可以用200。如果会话已过期,那么您将获得401。在401的情况下,您只需重定向回登录页面。
有很多方法可以传达这种情况也发生在用户身上。一种方法是像您已经做的那样在本地存储中保存一些状态,并假设用户可以导航到登录页。无论如何都不会加载任何敏感数据,因为数据应该位于经过身份验证的端点之后。
在任何401的情况下,你可以重定向到登录,或者向用户显示一个错误,说"看起来你的会话已经过期,点击这里重新登录。"。