web-dev-qa-db-fra.com

Vérifiez si vous êtes connecté - React Router App ES6

J'écris une application React . Js (v15.3) en utilisant react-router (v2.8.1) et la syntaxe ES6 . Je ne parviens pas à obtenir le code du routeur pour intercepter toutes les transitions entre les pages afin de vérifier si l'utilisateur doit d'abord se connecter.

Ma méthode de rendu de premier niveau est très simple (l'application est également triviale):

 render()
   {
      return (
         <Router history={hashHistory}>
            <Route path="/" component={AppMain}>
               <Route path="login" component={Login}/>
               <Route path="logout" component={Logout}/>
               <Route path="subject" component={SubjectPanel}/>
               <Route path="all" component={NotesPanel}/>
            </Route>
         </Router>
      );
   }

Tous les exemples sur le Web utilisent du code ES5 ou des versions antérieures de react-router (antérieures à la version 2), et mes diverses tentatives avec mixins (obsolète) et willTransitionTo (jamais appelée) ont échoué.

Comment puis-je configurer une «fonction d'intercepteur» globale pour obliger les utilisateurs à s'authentifier avant de placer la page demandée?

13
Serge Merzliakov

Cette version du rappel onEnter a finalement fonctionné pour react-router (v2.8):

 requireAuth(nextState,
               replace)
   {
      if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
         replace('/login')
   }

Le lien qui explique les différences de redirection du routeur react-router entre V1 et v2 est ici . Section pertinente citée ci-dessous:

Likewise, redirecting from an onEnter hook now also uses a location descriptor.

// v1.0.x
(nextState, replaceState) => replaceState(null, '/foo')
(nextState, replaceState) => replaceState(null, '/foo', { the: 'query' })

// v2.0.0
(nextState, replace) => replace('/foo')
(nextState, replace) => replace({ pathname: '/foo', query: { the: 'query' } })

Liste complète des codes ci-dessous (react-router version 2.8.1):

requireAuth(nextState,
               replace)
{
   if(!this.authenticated()) // pseudocode - SYNCHRONOUS function (cannot be async without extra callback parameter to this function)
     replace('/login');
}

render() {
  return (
     <Router history={hashHistory}>
        <Route path="/" component={AppMain}>
           <Route path="login" component={Login}/>
           <Route path="logout" component={Logout}/>
           <Route path="subject" component={SubjectPanel} onEnter={this.requireAuth}/>
           <Route path="all" component={NotesPanel} onEnter={this.requireAuth}/>
        </Route>
     </Router>
  );
}
0
Serge Merzliakov

Chaque route a un raccordement onEnter qui est appelé avant que la transition ne se produise. Gérez le crochet onEnter avec une fonction requireAuth personnalisée.

<Route path="/search" component={Search} onEnter={requireAuth} />

Un exemple requireAuth est présenté ci-dessous. Si l'utilisateur est authentifié, passez par next (). Sinon, remplacez le chemin par/login et effectuez la transition via next (). Le nom de chemin actuel est également transmis au nom de connexion, ce qui permet à l'utilisateur de se rediriger vers le chemin initialement demandé.

function requireAuth(nextState, replace, next) {
  if (!authenticated) {
    replace({
      pathname: "/login",
      state: {nextPathname: nextState.location.pathname}
    });
  }
  next();
}
11
vijayst

Dans la v4, vous créez simplement un composant de route qui vérifie si uses est authentifié et renvoie les composants suivants et, bien sûr, le composant suivant peut être d'autres routes.

import React, { Component } from 'react';
import PropTypes from 'prop-types';

import { connect } from 'react-redux';
import { bindActionCreators } from 'redux';
import { Route, Redirect } from 'react-router-dom';

import AuthMiddleware from 'modules/middlewares/AuthMiddleware';

class PrivateRoute extends Component {
  static propTypes = {
    component: PropTypes.func.isRequired,
    isAuthenticated: PropTypes.bool,
    isLoggedIn: PropTypes.func.isRequired,
    isError: PropTypes.bool.isRequired
  };

  static defaultProps = {
    isAuthenticated: false
  };

  constructor(props) {
    super(props);
    if (!props.isAuthenticated) {
      setTimeout(() => {
        props.isLoggedIn();
      }, 5);
    }
  }

  componentWillMount() {
    if (this.props.isAuthenticated) {
      console.log('authenticated');
    } else {
      console.log('not authenticated');
    }
  }
  componentWillUnmount() {}

  render() {
    const { isAuthenticated, component, isError, ...rest } = this.props;
    if (isAuthenticated !== null) {
      return (
        <Route
          {...rest}
          render={props => (
            isAuthenticated ? (
              React.createElement(component, props)
            ) : (
              <Redirect
                to={{
                  pathname: isError ? '/login' : '/welcome',
                  state: { from: props.location }
                }}
              />
            )
          )}
        />
      );
    } return null;
  }

}

const mapStateToProps = (state) => {
  return {
    isAuthenticated: state.auth.isAuthenticated,
    isError: state.auth.isError
  };
};

const mapDispatchToProps = (dispatch) => {
  return bindActionCreators({
    isLoggedIn: () => AuthMiddleware.isLoggedIn()
  }, dispatch);
};

export default connect(mapStateToProps, mapDispatchToProps)(PrivateRoute);
4
eersteam