web-dev-qa-db-fra.com

Comment restreindre l'accès aux routes dans react-router?

Est-ce que quelqu'un sait comment restreindre l'accès à des routes particulières dans react-router? Je souhaite vérifier si l'utilisateur est connecté avant d'autoriser l'accès à un itinéraire particulier. Je pensais que ce serait simple, mais les documents ne savent pas comment le faire.

Est-ce quelque chose que je devrais mettre en place là où je définis mon <Route> _ composants, ou devrais-je le manipuler dans mes gestionnaires de composants?

<Route handler={App} path="/">
  <NotFoundRoute handler={NotFound} name="not-found"/>
  <DefaultRoute handler={Login} name="login"/>
  <Route handler={Todos} name="todos"/> {/* I want this to be restricted */}
</Route>
60
Tanner Semerad

Mise à jour (16 août 2019)

Dans react-router v4 et en utilisant React Crochets cela semble un peu différent. Commençons par votre App.js.

export default function App() {
  const [isAuthenticated, userHasAuthenticated] = useState(false);

  useEffect(() => {
    onLoad();
  }, []);

  async function onLoad() {
    try {
      await Auth.currentSession();
      userHasAuthenticated(true);
    } catch (e) {
      alert(e);
    }
  }

  return (
    <div className="App container">
      <h1>Welcome to my app</h1>
      <Switch>
        <UnauthenticatedRoute
          path="/login"
          component={Login}
          appProps={{ isAuthenticated }}
        />
        <AuthenticatedRoute
          path="/todos"
          component={Todos}
          appProps={{ isAuthenticated }}
        />
        <Route component={NotFound} />
      </Switch>
    </div>
  );
}

Nous utilisons une bibliothèque Auth pour vérifier si l'utilisateur est actuellement authentifié. Remplacez-le par votre fonction de vérification d'authentification. Si tel est le cas, nous définissons le drapeau isAuthenticated sur true. Nous le faisons lors du premier chargement de notre application. Il convient également de mentionner que vous voudrez peut-être ajouter un signe de chargement sur votre application lors de l'exécution de la vérification automatique, afin de ne pas afficher la page de connexion à chaque fois que vous actualisez la page.

Ensuite, nous passons le drapeau à nos itinéraires. Nous créons deux types de routes AuthenticatedRoute et UnauthenticatedRoute.

Le AuthenticatedRoute.js ressemble à ça.

export default function AuthenticatedRoute({ component: C, appProps, ...rest }) {
  return (
    <Route
      {...rest}
      render={props =>
        appProps.isAuthenticated
          ? <C {...props} {...appProps} />
          : <Redirect
              to={`/login?redirect=${props.location.pathname}${props.location.search}`}
            />}
    />
  );
}

Il vérifie si isAuthenticated est défini sur true. Si c'est le cas, le composant souhaité sera rendu. Si non, alors il va rediriger vers la page de connexion.

Le UnauthenticatedRoute.js d'autre part ressemble à ceci.

export default ({ component: C, appProps, ...rest }) =>
  <Route
    {...rest}
    render={props =>
      !appProps.isAuthenticated
        ? <C {...props} {...appProps} />
        : <Redirect to="/" />}
  />;

Dans ce cas, si isAuthenticated est défini sur false, il rendra le composant souhaité. Et s'il est défini sur true, il vous enverra à la page d'accueil.

Vous en trouverez des versions détaillées dans notre guide - https://serverless-stack.com/chapters/create-a-route-that-redirects.html .

Ancienne version

La réponse acceptée est correcte mais les Mixins sont considérés comme nocifs ( https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html ) par le React équipe.

Si quelqu'un tombe sur cette question et cherche la manière recommandée de le faire, je suggérerais d'utiliser des composants d'ordre supérieur au lieu de Mixins.

Voici un exemple de HOC qui vérifiera si l'utilisateur est connecté avant de continuer. Et si l'utilisateur n'est pas connecté, il vous redirigera vers la page de connexion. Ce composant utilise un accessoire appelé isLoggedIn, c’est-à-dire un indicateur que votre application peut stocker pour indiquer si l’utilisateur est connecté.

import React from 'react';
import { withRouter } from 'react-router';

export default function requireAuth(Component) {

  class AuthenticatedComponent extends React.Component {

    componentWillMount() {
      this.checkAuth();
    }

    checkAuth() {
      if ( ! this.props.isLoggedIn) {
        const location = this.props.location;
        const redirect = location.pathname + location.search;

        this.props.router.Push(`/login?redirect=${redirect}`);
      }
    }

    render() {
      return this.props.isLoggedIn
        ? <Component { ...this.props } />
        : null;
    }

  }

  return withRouter(AuthenticatedComponent);
}

Et pour utiliser ce COH, enroulez-le simplement autour de vos itinéraires. Dans le cas de votre exemple, ce serait:

<Route handler={requireAuth(Todos)} name="todos"/>

Je couvre ceci et quelques autres sujets dans un tutoriel détaillé étape par étape ici - https://serverless-stack.com/chapters/create-a-hhc-that-checks-auth.html =

62
jayair

Il existe (maintenant?) Un exemple dans React Les documents du routeur 4 pour Redirect

import { Route, Redirect } from 'react-router'

<Route exact path="/" render={() => (
  loggedIn ? (
    <Redirect to="/dashboard"/>
  ) : (
    <PublicHomePage/>
  )
)}/>
23
jacob

Si vous souhaitez utiliser l'authentification sur l'ensemble de votre application, vous devez stocker des données au niveau de l'application (par exemple, un jeton). Vous pouvez configurer deux React mixins responsables de la gestion de l'objet $auth. Cet objet ne devrait pas être disponible en dehors de ces deux mixins. En voici un exemple:

define('userManagement', function() {
    'use strict';

    var $auth = {
        isLoggedIn: function () {
            // return something, e.g. using server-stored data
        }
    };

    return {
        Authenticator: {
           login: function(username, password) {
               // modify $auth object, or call server, or both
           }
        },

        NeedsAuthenticatedUser: {
            statics: {
                willTransitionTo: function (transition) {
                    if (!$auth.isLoggedIn()) {
                        transition.abort();
                    }
                }
            }
        }
    };
});

Ensuite, vous pouvez simplement mélanger Authenticator en mélangeant vos composants de connexion (écran de connexion, popup de connexion, etc.) et appeler la fonction this.login Lorsque vous disposez de toutes les données nécessaires.

Le plus important est de protéger vos composants en mélangeant dans NeedsAuthenticatedUser mixin. Chaque composant nécessitant un utilisateur authentifié devra ressembler à cela:

var um = require('userManagement');

var ProtectedComponent = React.createClass({
    mixins: [um.NeedsAuthenticatedUser]
    // ...
}

Notez que NeedsAuthenticatedUser utilise l’API de réacteur-routeur (willTransitionTo et transition.abort()).

2
Michał Płachta

react-router encourage une approche déclarative pour votre routeur. Vous devez le rendre aussi bête que possible et éviter de placer votre logique de routage dans vos composants.

Voici comment vous pouvez le faire (en supposant que vous passiez le loggedIn prop):

const DumbRouter = ({ loggedIn }) => (
  <Router history={history}>
    <Switch>
      {[
        !loggedIn && LoggedOutRoutes,
        loggedIn && LoggedInRouter,
        <Route component={404Route} />
      ]}
    </Switch>
  </Router>
);

const LoggedInRoutes = [
  <Route path="/" component={Profile} />
];

const LoggedOutRoutes = [
  <Route path="/" component={Login} />
];
1
gwendall

private-route.tsx

import {Redirect, Route, RouteProps} from 'react-router';
import * as React from 'react';

interface PrivateRouteProps extends RouteProps {
  /**
   * '/login' for example.
   */
  redirectTo: string;

  /**
   * If true, won't redirect.
   * We are using a function instead of a bool, a bool does not seem to be updated
   * after having successfully authenticated.
   */
  isLogged: () => boolean;
}


export function PrivateRoute(props: PrivateRouteProps) {
  // `component: Component` is not typing, it assign the value to a new variable.
  let { isLogged, redirectTo, component: Component, ...rest }: any = props;

  // error: JSX type element Component does not have call signature or ... AVOIDED BY ADDING ANY, still work,
  // and did not find a proper way to fix it.
  return <Route {...rest} render={(props) => (
    isLogged()
      ? <Component {...props}/>
      : <Redirect to={{
        pathname: redirectTo,
        state: { from: props.location }
      }} />
  )} />;
}

Usage:

        <PrivateRoute exact={true} 
                      path="/admin/" 
                      redirectTo={'/admin/login'} 
                      isLogged={this.loginService.isLogged} 
                      component={AdminDashboardPage}/>
        <Route path="/admin/login/" component={AdminLoginPage}/>

Basé sur https://tylermcginnis.com/react-router-protected-routes-authentication/ .

0
Ambroise Rabier