route react helmet doom change reactjs local-storage redux react-router react-redux

reactjs - helmet - react router doom



En React Router, ¿cómo permanecer conectado en el estado incluso actualizar la página? (2)

Estoy haciendo el sitio web con React y React Router con Redux. Muchas rutas (páginas) requieren iniciar sesión. Puedo redireccionar para iniciar sesión si el usuario no ha iniciado sesión de esta manera:

function requireAuth(nextState, replace) { let loggedIn = store.getState().AppReducer.UserReducer.loggedIn; if(!loggedIn) { replace({ pathname: ''/login'', state: { nextpathname: nextState.location.pathname } }); } } ReactDOM.render( <Provider store={store}> <Router history={history}> <Route path="/" component={App}> <IndexRoute component={Index} /> <Route path="login" component={Login} /> <Route path="register" component={Register} /> <Route path="dashboard" component={Graph} onEnter={requireAuth}> ... some other route requires logged in ... </Route> </Route> </Router> </Provider>, document.getElementById(''entry'') );

Consulte el código. Utilicé onEnter hook para redirigir a la ruta ''/ login'' si el usuario no ha iniciado sesión. Los datos para verificar que el usuario inició sesión están en la tienda y se actualizarán después de que el usuario haya iniciado sesión.

Funciona perfectamente, pero el problema es cuando actualizo la página, la tienda se restablecerá y el usuario no ha iniciado sesión en el estado anterior.

Sé que esto sucede porque la tienda Redux es solo un almacenamiento de memoria, por lo que la página refesh perderá todos los datos.

Verifique que la sesión del servidor en cada actualización pueda funcionar, pero esto puede ser una solicitud excesiva, por lo que parece una mala idea.

Guardar los datos de estado registrados en localStorage podría ser un trabajo, pero en este caso, debería verificar que todas las llamadas AJAX fallan en la solicitud rechazada porque la sesión ha caducado o no existe como algo, y parece ser una mala idea.

¿Hay alguna manera de resolver este problema más claramente? Mi sitio web utilizará a mucha gente, así que quiero reducir las llamadas XHR lo más posible.

Cualquier consejo será muy apreciado.


¿Por qué no usar sessionStorage con el estado de inicio de sesión y la fecha de vencimiento? Tendrá que escribir más código para verificar el estado de SessionStorage, pero esa es la única manera en mi opinión de que puede guardar la llamada XHR para que no sea enviada.


Otra forma de hacerlo es usar los tokens web JSON (JWT) que se requieren para cada ruta, y localStorage para verificar el JWT.

TL; DR

  • En el extremo frontal tiene una ruta de inicio de sesión y de inicio de sesión que solicita a su servidor un JWT de acuerdo con la autenticación en el servidor. Una vez pasado el JWT apropiado, establecería una propiedad de estado en verdadero. Puede tener una ruta de cierre de sesión que le permita al usuario establecer este estado en falso.

  • El index.js que contiene sus rutas puede verificar el almacenamiento local antes de renderizar, eliminando así su problema con la pérdida del estado en la actualización pero manteniendo cierta seguridad.

  • Todas las rutas que requieren autenticación en su aplicación se representan a través de un Componente compuesto y se aseguran con la necesidad de tener JWT en el encabezado para la autorización en la API del servidor.

Configurar esto toma un poco de tiempo, pero hará que su aplicación sea "razonablemente" segura.

Para resolver su problema:

Verifique el almacenamiento local antes de las rutas en su archivo index.js como se muestra a continuación, actualizando el estado a autenticado si es necesario.

La aplicación mantiene la seguridad con el hecho de que la API está protegida por JWT, lo que resolvería su problema de actualización y mantendría un enlace seguro a su servidor y sus datos.

Así en las rutas tendrías algo como esto:

index.js

import React from ''react''; import ReactDOM from ''react-dom''; import { Provider } from ''react-redux''; import { createStore, applyMiddleware, compose } from ''redux''; import { Router, Route, browserHistory, IndexRoute } from ''react-router''; import reduxThunk from ''redux-thunk''; import { AUTHENTICATE_THE_USER } from ''./actions/types''; import RequireAuth from ''./components/auth/require_auth''; import reducers from ''./reducers''; /* ...import necessary components */ const createStoreWithMiddleware = compose(applyMiddleware(reduxThunk))(createStore); const store = createStoreWithMiddleware(reducers); /* ... */ // Check for token and update application state if required const token = localStorage.getItem(''token''); if (token) { store.dispatch({ type: AUTHENTICATE_THE_USER }); } /* ... */ ReactDOM.render( <Provider store={store}> <Router history={history}> <Route path="/" component={App}> <IndexRoute component={Index} /> <Route path="login" component={Login} /> <Route path="register" component={Register} /> <Route path="dashboard" component={RequireAuth{Graph}} /> <Route path="isauthenticated" component={RequireAuth(IsAuthenticated)} /> ... some other route requires logged in ... </Route> </Router> </Provider> , .getElementById(''entry''));

RequiredAuth es el componente compuesto, mientras que Graph e IsAuthenticated (pueden ser cualquier número de componentes con nombres apropiados) requieren que el estado state.authenticated sea ​​verdadero.

Los Componentes, en este caso Graph e IsAuthenticated procesaron si el state.authenticated es verdadero. De lo contrario, los valores predeterminados vuelven a la ruta raíz.

Luego, podría crear un Componente compuesto como este, a través del cual se representarán todas las rutas. Verificará que el estado en el que está en espera de si el usuario está o no autenticado (un valor booleano) es verdadero antes de renderizar.

require_auth.js

import React, { Component } from ''react''; import { connect } from ''react-redux''; export default function (ComposedComponent) { // If user not authenticated render out to root class Authentication extends Component { static contextTypes = { router: React.PropTypes.object }; componentWillMount() { if (!this.props.authenticated) { this.context.router.push(''/''); } } componentWillUpdate(nextProps) { if (!nextProps.authenticated) { this.context.router.push(''/''); } } render() { return <ComposedComponent {...this.props} />; } } function mapStateToProps(state) { return { authenticated: state.authenticated }; } return connect(mapStateToProps)(Authentication); }

En el lado de registro / inicio de sesión, puede crear una acción que almacene el JWT y configure el estado para autenticarse a través de un creador de acción -> redux store. Este ejemplo hace uso de axios para ejecutar el ciclo de respuesta de solicitud HTTP asíncrono.

export function signinUser({ email, password }) { // Note using the npm package ''redux-thunk'' // giving direct access to the dispatch method return function (dispatch) { // Submit email and password to server axios.post(`${API_URL}/signin`, { email, password }) .then(response => { // If request is good update state - user is authenticated dispatch({ type: AUTHENTICATE_THE_USER }); // - Save the JWT in localStorage localStorage.setItem(''token'', response.data.token); // - redirect to the route ''/isauthenticated'' browserHistory.push(''/isauthenticated''); }) .catch(() => { // If request is bad show an error to the user dispatch(authenticationError(''Incorrect email or password!'')); }); }; }

También necesitaría configurar su tienda (Redux en este caso) y el creador de acciones, por supuesto.

La seguridad "real" viene de la parte de atrás. Y para hacer esto, usa localStorage para mantener el JWT en el extremo delantero y pasarlo en el encabezado a cualquier llamada a la API que tenga información confidencial / protegida.

Crear y analizar el JWT para usuarios en la API del servidor es otro paso. He encontrado el pasaporte para ser eficaz.