Comment implémenter des routes authentifiées dans React Router 4?

122

J'essayais d'implémenter des routes authentifiées mais j'ai trouvé que React Router 4 empêche maintenant que cela fonctionne:

<Route exact path="/" component={Index} />
<Route path="/auth" component={UnauthenticatedWrapper}>
    <Route path="/auth/login" component={LoginBotBot} />
</Route>
<Route path="/domains" component={AuthenticatedWrapper}>
    <Route exact path="/domains" component={DomainsIndex} />
</Route>

L'erreur est:

Attention: vous ne devez pas utiliser <Route component>et <Route children>dans le même itinéraire; <Route children>sera ignoré

Dans ce cas, quelle est la bonne façon de mettre en œuvre cela?

Il apparaît dans la documentation react-router(v4), il suggère quelque chose comme

<Router>
    <div>
    <AuthButton/>
    <ul>
        <li><Link to="/public">Public Page</Link></li>
        <li><Link to="/protected">Protected Page</Link></li>
    </ul>
    <Route path="/public" component={Public}/>
    <Route path="/login" component={Login}/>
    <PrivateRoute path="/protected" component={Protected}/>
    </div>
</Router>

Mais est-il possible d'y parvenir en regroupant plusieurs itinéraires?


METTRE À JOUR

Ok, après quelques recherches, je suis venu avec ceci:

import React, {PropTypes} from "react"
import {Route} from "react-router-dom"

export default class AuthenticatedRoute extends React.Component {
  render() {
    if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <Route {...this.props} />
  }
}

AuthenticatedRoute.propTypes = {
  isLoggedIn: PropTypes.bool.isRequired,
  component: PropTypes.element,
  redirectToLogin: PropTypes.func.isRequired
}

Il est correct d'envoyer une action dans render()ce sens. Cela ne semble pas vraiment correct avec componentDidMountou avec un autre crochet non plus?

Jiew Meng
la source
mieux faire sur componentWillMount si vous n'utilisez pas le rendu côté serveur.
mfahadi
@mfahadi, merci pour votre contribution. Je n'utilise pas encore SSR, mais si je veux l'utiliser à l'avenir, est-ce que je le garde en rendu? De plus, si l'utilisateur est redirigé componentWillMount, pourra-t-il jamais voir la sortie rendue même pendant une fraction de seconde?
Jiew Meng
Je suis vraiment désolé de dire que ce componentWillMount()n'est pas appelé sur SSR, c'est componentDidMount()que ce n'est pas appelé. comme componentWillMount()on l'a appelé auparavant render(), de sorte que l'utilisateur ne verra rien de nouveau composant. c'est donc le meilleur endroit pour vérifier.
mfahadi
1
vous pouvez simplement utiliser la <Redirect to="/auth"> documentation au lieu d'appeler l'action de répartition
Fuzail l'Corder

Réponses:

239

Vous allez vouloir utiliser le Redirectcomposant. Il existe plusieurs approches différentes de ce problème. En voici un que j'aime, avoir un composant PrivateRoute qui prend dans un authedaccessoire, puis rend basé sur ces accessoires.

function PrivateRoute ({component: Component, authed, ...rest}) {
  return (
    <Route
      {...rest}
      render={(props) => authed === true
        ? <Component {...props} />
        : <Redirect to={{pathname: '/login', state: {from: props.location}}} />}
    />
  )
}

Maintenant, tes Routes peuvent ressembler à quelque chose comme ça

<Route path='/' exact component={Home} />
<Route path='/login' component={Login} />
<Route path='/register' component={Register} />
<PrivateRoute authed={this.state.authed} path='/dashboard' component={Dashboard} />

Si vous êtes toujours confus, j'ai écrit ce post qui peut vous aider - Routes protégées et authentification avec React Router v4

Tyler McGinnis
la source
2
Oh, c'est similaire à ma solution, mais il utilise <Redirect />. Le problème est <Redirect />ne semble pas fonctionner avec redux dans mon cas? J'ai besoin d'envoyer une action
Jiew Meng
3
Je ne sais pas pourquoi, mais l'ajout a state: {from: props.location}}}causé un maximum call stack exceeded. J'ai dû l'enlever. Pouvez-vous expliquer pourquoi cette option est utile @Tyler McGinnis?
martpie
@KeitIG ​​C'est étrange. C'est utile car il vous indique d'où vous venez. Un exemple serait que si vous vouliez que l'utilisateur s'authentifie, une fois qu'il s'est authentifié, ramenez-le à la page à laquelle il essayait d'accéder avant de le rediriger.
Tyler McGinnis
6
@faraz Ceci explique la ({component: Component, ...rest})syntaxe. J'ai eu la même question lol! stackoverflow.com/a/43484565/6502003
protoEvangelion
2
@TylerMcGinnis Que faire si nous devons utiliser la fonction de rendu pour passer des accessoires au composant?
C Bauer
16

Tnx Tyler McGinnis pour la solution. Je fais mon idée à partir de l'idée de Tyler McGinnis.

const DecisionRoute = ({ trueComponent, falseComponent, decisionFunc, ...rest }) => {
  return (
    <Route
      {...rest}

      render={
        decisionFunc()
          ? trueComponent
          : falseComponent
      }
    />
  )
}

Vous pouvez mettre en œuvre cela comme ça

<DecisionRoute path="/signin" exact={true}
            trueComponent={redirectStart}
            falseComponent={SignInPage}
            decisionFunc={isAuth}
          />

decisionFunc juste une fonction qui retourne vrai ou faux

const redirectStart = props => <Redirect to="/orders" />
MrDuDuDu
la source
8

(Utilisation de Redux pour la gestion de l'état)

Si l'utilisateur essaie d'accéder à une URL, je vais d'abord vérifier si le jeton d'accès est disponible, sinon rediriger vers la page de connexion.Une fois que l'utilisateur se connecte à l'aide de la page de connexion, nous le stockons dans le stockage local ainsi que dans notre état redux. (stockage local ou cookies .. nous gardons ce sujet hors de son contexte pour l'instant).
depuis l'état de redux comme mis à jour et les routes privées seront rendues. maintenant nous avons un jeton d'accès donc nous allons rediriger vers la page d'accueil.

Stockez également les données de charge utile d'autorisation décodées dans l'état redux et transmettez-les au contexte de réaction. (Nous n'avons pas besoin d'utiliser le contexte, mais pour accéder à l'autorisation dans l'un de nos composants enfants imbriqués, il est facile d'accéder à partir du contexte au lieu de connecter chaque composant enfant à redux).

Toutes les routes qui n'ont pas besoin de rôles spéciaux peuvent être accédées directement après la connexion .. Si elle a besoin d'un rôle comme admin (nous avons fait une route protégée qui vérifie s'il avait le rôle souhaité sinon redirige vers un composant non autorisé)

de même dans l'un de vos composants si vous devez désactiver le bouton ou quelque chose en fonction du rôle.

tu peux simplement faire de cette manière

const authorization = useContext(AuthContext);
const [hasAdminRole] = checkAuth({authorization, roleType:"admin"});
const [hasLeadRole] = checkAuth({authorization, roleType:"lead"});
<Button disable={!hasAdminRole} />Admin can access</Button>
<Button disable={!hasLeadRole || !hasAdminRole} />admin or lead can access</Button>

Alors que faire si l'utilisateur essaie d'insérer un jeton factice dans localstorage. Comme nous avons un jeton d'accès, nous redirigerons vers le composant d'accueil. Mon composant domestique effectuera un appel au repos pour récupérer des données, puisque le jeton jwt était factice, l'appel au repos retournera un utilisateur non autorisé. Donc, j'appelle la déconnexion (ce qui effacera le stockage local et redirigera à nouveau vers la page de connexion). Si la page d'accueil contient des données statiques et ne fait aucun appel d'API (alors vous devriez avoir un appel API de vérification de jeton dans le backend afin de pouvoir vérifier si le jeton est RÉEL avant de charger la page d'accueil)

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import { Router, Route, Switch } from 'react-router-dom';
import history from './utils/history';


import Store from './statemanagement/store/configureStore';
import Privateroutes from './Privateroutes';
import Logout from './components/auth/Logout';

ReactDOM.render(
  <Store>
    <Router history={history}>
      <Switch>
        <Route path="/logout" exact component={Logout} />
        <Route path="/" exact component={Privateroutes} />
        <Route path="/:someParam" component={Privateroutes} />
      </Switch>
    </Router>
  </Store>,
  document.querySelector('#root')
);

History.js

import { createBrowserHistory as history } from 'history';

export default history({});

Privateroutes.js

import React, { Fragment, useContext } from 'react';
import { Route, Switch, Redirect } from 'react-router-dom';
import { connect } from 'react-redux';
import { AuthContext, checkAuth } from './checkAuth';
import App from './components/App';
import Home from './components/home';
import Admin from './components/admin';
import Login from './components/auth/Login';
import Unauthorized from './components/Unauthorized ';
import Notfound from './components/404';

const ProtectedRoute = ({ component: Component, roleType, ...rest })=> { 
const authorization = useContext(AuthContext);
const [hasRequiredRole] = checkAuth({authorization, roleType});
return (
<Route
  {...rest}
  render={props => hasRequiredRole ? 
  <Component {...props} /> :
   <Unauthorized {...props} />  } 
/>)}; 

const Privateroutes = props => {
  const { accessToken, authorization } = props.authData;
  if (accessToken) {
    return (
      <Fragment>
       <AuthContext.Provider value={authorization}>
        <App>
          <Switch>
            <Route exact path="/" component={Home} />
            <Route path="/login" render={() => <Redirect to="/" />} />
            <Route exact path="/home" component={Home} />
            <ProtectedRoute
            exact
            path="/admin"
            component={Admin}
            roleType="admin"
          />
            <Route path="/404" component={Notfound} />
            <Route path="*" render={() => <Redirect to="/404" />} />
          </Switch>
        </App>
        </AuthContext.Provider>
      </Fragment>
    );
  } else {
    return (
      <Fragment>
        <Route exact path="/login" component={Login} />
        <Route exact path="*" render={() => <Redirect to="/login" />} />
      </Fragment>
    );
  }
};

// my user reducer sample
// const accessToken = localStorage.getItem('token')
//   ? JSON.parse(localStorage.getItem('token')).accessToken
//   : false;

// const initialState = {
//   accessToken: accessToken ? accessToken : null,
//   authorization: accessToken
//     ? jwtDecode(JSON.parse(localStorage.getItem('token')).accessToken)
//         .authorization
//     : null
// };

// export default function(state = initialState, action) {
// switch (action.type) {
// case actionTypes.FETCH_LOGIN_SUCCESS:
//   let token = {
//                  accessToken: action.payload.token
//               };
//   localStorage.setItem('token', JSON.stringify(token))
//   return {
//     ...state,
//     accessToken: action.payload.token,
//     authorization: jwtDecode(action.payload.token).authorization
//   };
//    default:
//         return state;
//    }
//    }

const mapStateToProps = state => {
  const { authData } = state.user;
  return {
    authData: authData
  };
};

export default connect(mapStateToProps)(Privateroutes);

checkAuth.js

import React from 'react';

export const AuthContext = React.createContext();

export const checkAuth = ({ authorization, roleType }) => {
  let hasRequiredRole = false;

  if (authorization.roles ) {
    let roles = authorization.roles.map(item =>
      item.toLowerCase()
    );

    hasRequiredRole = roles.includes(roleType);
  }

  return [hasRequiredRole];
};

ÉCHANTILLON DE JWT DÉCODÉ

{
  "authorization": {
    "roles": [
      "admin",
      "operator"
    ]
  },
  "exp": 1591733170,
  "user_id": 1,
  "orig_iat": 1591646770,
  "email": "hemanthvrm@stackoverflow",
  "username": "hemanthvrm"
}
Hemanthevrm
la source
Et comment gérez-vous l'accès direct à Signin? Si un utilisateur sait qu'il n'est pas connecté, il devrait avoir la possibilité d'accéder directement à la connexion, n'est-ce pas?
carkod
@carkod ... Par défaut, s'il tente d'accéder à une route, il sera redirigé vers la page de connexion ... (car il n'aura pas de jeton)
Hemanthvrm
@carkod .. une fois que l'utilisateur a cliqué sur la déconnexion ou bien mon jeton d'actualisation jwt expire .. j'appelle la fonction de déconnexion où j'efface le stockage local et la fenêtre d'actualisation ... donc localstorage n'aura pas de jeton..il sera automatiquement redirigé vers la page de connexion
Hemanthvrm
J'ai une meilleure version de celui-ci pour ceux qui utilisent redux .. mettra à jour ma réponse dans quelques jours .. merci -
Hemanthvrm
3

installer react-router-dom

puis créez deux composants, l'un pour les utilisateurs valides et l'autre pour les utilisateurs non valides.

essayez ceci sur app.js

import React from 'react';

import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect
} from 'react-router-dom';

import ValidUser from "./pages/validUser/validUser";
import InValidUser from "./pages/invalidUser/invalidUser";
const loggedin = false;

class App extends React.Component {
 render() {
    return ( 
      <Router>
      <div>
        <Route exact path="/" render={() =>(
          loggedin ? ( <Route  component={ValidUser} />)
          : (<Route component={InValidUser} />)
        )} />

        </div>
      </Router>
    )
  }
}
export default App;
José G Varanam
la source
4
Par itinéraire? Cela ne va pas évoluer.
Jim G.
3

Basé sur la réponse de @Tyler McGinnis . J'ai fait une approche différente en utilisant la syntaxe ES6 et des routes imbriquées avec des composants enveloppés:

import React, { cloneElement, Children } from 'react'
import { Route, Redirect } from 'react-router-dom'

const PrivateRoute = ({ children, authed, ...rest }) =>
  <Route
    {...rest}
    render={(props) => authed ?
      <div>
        {Children.map(children, child => cloneElement(child, { ...child.props }))}
      </div>
      :
      <Redirect to={{ pathname: '/', state: { from: props.location } }} />}
  />

export default PrivateRoute

Et en l'utilisant:

<BrowserRouter>
  <div>
    <PrivateRoute path='/home' authed={auth}>
      <Navigation>
        <Route component={Home} path="/home" />
      </Navigation>
    </PrivateRoute>

    <Route exact path='/' component={PublicHomePage} />
  </div>
</BrowserRouter>
Felipe Augusto
la source
2

Je sais que cela fait un moment, mais je travaille sur un package npm pour les routes privées et publiques.

Voici comment créer un itinéraire privé:

<PrivateRoute exact path="/private" authed={true} redirectTo="/login" component={Title} text="This is a private route"/>

Et vous pouvez également créer des routes publiques auxquelles seul un utilisateur non autorisé peut accéder

<PublicRoute exact path="/public" authed={false} redirectTo="/admin" component={Title} text="This route is for unauthed users"/>

J'espère que ça aide!

Gonzalo Cañada
la source
pouvez-vous s'il vous plaît fournir plus d'exemples, y compris toutes les importations et enveloppements, par exemple dans 2 routes publiques, 2 routes privées et 2 PropsRoute, dans le fichier App.js principal? merci
MH
2

J'ai implémenté en utilisant

<Route path='/dashboard' render={() => (
    this.state.user.isLoggedIn ? 
    (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
    (<Redirect to="/login" />)
)} />

Les accessoires d'authentification seront transmis aux composants, par exemple l'inscription en utilisant quel état d'utilisateur peut être modifié. AppRoutes complet

import React from 'react';
import { Switch, Route } from 'react-router-dom';
import { Redirect } from 'react-router';

import Home from '../pages/home';
import Login from '../pages/login';
import Signup from '../pages/signup';
import Dashboard from '../pages/dashboard';

import { config } from '../utils/Config';

export default class AppRoutes extends React.Component {

    constructor(props) {
        super(props);

        // initially assuming that user is logged out
        let user = {
            isLoggedIn: false
        }

        // if user is logged in, his details can be found from local storage
        try {
            let userJsonString = localStorage.getItem(config.localStorageKey);
            if (userJsonString) {
                user = JSON.parse(userJsonString);
            }
        } catch (exception) {
        }

        // updating the state
        this.state = {
            user: user
        };

        this.authenticate = this.authenticate.bind(this);
    }

    // this function is called on login/logout
    authenticate(user) {
        this.setState({
            user: user
        });

        // updating user's details
        localStorage.setItem(config.localStorageKey, JSON.stringify(user));
    }

    render() {
        return (
            <Switch>
                <Route exact path='/' component={Home} />
                <Route exact path='/login' render={() => <Login authenticate={this.authenticate} />} />
                <Route exact path='/signup' render={() => <Signup authenticate={this.authenticate} />} />
                <Route path='/dashboard' render={() => (
                    this.state.user.isLoggedIn ? 
                            (<Dashboard authenticate={this.authenticate} user={this.state.user} />) : 
                            (<Redirect to="/login" />)
                )} />
            </Switch>
        );
    }
} 

Consultez le projet complet ici: https://github.com/varunon9/hello-react

Varun Kumar
la source
1

Il semble que votre hésitation soit à créer votre propre composant, puis à distribuer la méthode de rendu? Eh bien, vous pouvez éviter les deux en utilisant simplement la renderméthode du <Route>composant. Pas besoin de créer un <AuthenticatedRoute>composant sauf si vous le souhaitez vraiment. Cela peut être aussi simple que ci-dessous. Notez la {...routeProps}diffusion en vous assurant de continuer à envoyer les propriétés du <Route>composant vers le composant enfant ( <MyComponent>dans ce cas).

<Route path='/someprivatepath' render={routeProps => {

   if (!this.props.isLoggedIn) {
      this.props.redirectToLogin()
      return null
    }
    return <MyComponent {...routeProps} anotherProp={somevalue} />

} />

Voir la documentation de rendu du React Router V4

Si vous souhaitez créer un composant dédié, il semble que vous soyez sur la bonne voie. Étant donné que React Router V4 est un routage purement déclaratif (il le dit directement dans la description), je ne pense pas que vous vous en sortiriez en mettant votre code de redirection en dehors du cycle de vie normal des composants. En regardant le code pour React Router lui - même , ils exécutent la redirection soit componentWillMountou componentDidMountselon qu'il s'agit ou non d'un rendu côté serveur. Voici le code ci-dessous, qui est assez simple et pourrait vous aider à vous sentir plus à l'aise avec l'emplacement de votre logique de redirection.

import React, { PropTypes } from 'react'

/**
 * The public API for updating the location programatically
 * with a component.
 */
class Redirect extends React.Component {
  static propTypes = {
    push: PropTypes.bool,
    from: PropTypes.string,
    to: PropTypes.oneOfType([
      PropTypes.string,
      PropTypes.object
    ])
  }

  static defaultProps = {
    push: false
  }

  static contextTypes = {
    router: PropTypes.shape({
      history: PropTypes.shape({
        push: PropTypes.func.isRequired,
        replace: PropTypes.func.isRequired
      }).isRequired,
      staticContext: PropTypes.object
    }).isRequired
  }

  isStatic() {
    return this.context.router && this.context.router.staticContext
  }

  componentWillMount() {
    if (this.isStatic())
      this.perform()
  }

  componentDidMount() {
    if (!this.isStatic())
      this.perform()
  }

  perform() {
    const { history } = this.context.router
    const { push, to } = this.props

    if (push) {
      history.push(to)
    } else {
      history.replace(to)
    }
  }

  render() {
    return null
  }
}

export default Redirect
Todd Chaffee
la source
1

Ma réponse précédente n'est pas évolutive. Voici ce que je pense être une bonne approche-

Vos itinéraires-

<Switch>
  <Route
    exact path="/"
    component={matchStateToProps(InitialAppState, {
      routeOpen: true // no auth is needed to access this route
    })} />
  <Route
    exact path="/profile"
    component={matchStateToProps(Profile, {
      routeOpen: false // can set it false or just omit this key
    })} />
  <Route
    exact path="/login"
    component={matchStateToProps(Login, {
      routeOpen: true
    })} />
  <Route
    exact path="/forgot-password"
    component={matchStateToProps(ForgotPassword, {
      routeOpen: true
    })} />
  <Route
    exact path="/dashboard"
    component={matchStateToProps(DashBoard)} />
</Switch>

L'idée est d'utiliser un wrapper dans les componentaccessoires qui renverrait le composant d'origine si aucune authentification n'est requise ou déjà authentifié sinon retournerait le composant par défaut, par exemple Login.

const matchStateToProps = function(Component, defaultProps) {
  return (props) => {
    let authRequired = true;

    if (defaultProps && defaultProps.routeOpen) {
      authRequired = false;
    }

    if (authRequired) {
      // check if loginState key exists in localStorage (Your auth logic goes here)
      if (window.localStorage.getItem(STORAGE_KEYS.LOGIN_STATE)) {
        return <Component { ...defaultProps } />; // authenticated, good to go
      } else {
        return <InitialAppState { ...defaultProps } />; // not authenticated
      }
    }
    return <Component { ...defaultProps } />; // no auth is required
  };
};
Varun Kumar
la source
si l'authentification n'est pas requise, ne passez pas le composant à la fonction matchStateToProps, vous élimineriez ainsi le besoin d'un drapeau
routeOpen
1

Voici l'itinéraire protégé simple et propre

const ProtectedRoute 
  = ({ isAllowed, ...props }) => 
     isAllowed 
     ? <Route {...props}/> 
     : <Redirect to="/authentificate"/>;
const _App = ({ lastTab, isTokenVerified })=> 
    <Switch>
      <Route exact path="/authentificate" component={Login}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/secrets" 
         component={Secrets}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/polices" 
         component={Polices}/>
      <ProtectedRoute 
         isAllowed={isTokenVerified} 
         exact 
         path="/grants" component={Grants}/>
      <Redirect from="/" to={lastTab}/>
    </Switch>

isTokenVerified est un appel de méthode pour vérifier le jeton d'autorisation, il renvoie essentiellement un booléen.

Anupam Maurya
la source
C'est la seule solution que j'ai trouvée pour fonctionner si vous transmettez un composant ou des enfants à l'itinéraire.
Shawn
Remarque: je viens d'appeler mon isTokenVerified () dans ma fonction ProtectedRoute et je n'ai pas eu besoin de passer le prop isAllowed sur toutes les routes.
Shawn
1

Voici comment je l'ai résolu avec React et Typescript. J'espère que ça aide !

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

const PrivateRoute: React.SFC<RouteProps> = ({ component: Component, ...rest }) => {
    if (!Component) {
      return null;
    }
    const isLoggedIn = true; // Add your provider here
    return (
      <Route
        {...rest}
            render={(props: RouteComponentProps<{}>) => isLoggedIn ? (<Component {...props} />) : (<Redirect to={{ pathname: '/', state: { from: props.location } }} />)}
      />
    );
  };

export default PrivateRoute;








<PrivateRoute component={SignIn} path="/signin" />

Max_Thom
la source
0
const Root = ({ session }) => {
  const isLoggedIn = session && session.getCurrentUser
  return (
    <Router>
      {!isLoggedIn ? (
        <Switch>
          <Route path="/signin" component={<Signin />} />
          <Redirect to="/signin" />
        </Switch>
      ) : (
        <Switch>
          <Route path="/" exact component={Home} />
          <Route path="/about" component={About} />
          <Route path="/something-else" component={SomethingElse} />
          <Redirect to="/" />
        </Switch>
      )}
    </Router>
  )
}
Fellow étranger
la source
0

Je cherchais également une réponse. Ici, toutes les réponses sont assez bonnes, mais aucune d'entre elles ne donne de réponses sur la façon dont nous pouvons l'utiliser si l'utilisateur lance l'application après l'avoir rouverte. (Je voulais dire en utilisant des cookies ensemble).

Pas besoin de créer même un composant privateRoute différent. Ci-dessous mon code

    import React, { Component }  from 'react';
    import { Route, Switch, BrowserRouter, Redirect } from 'react-router-dom';
    import { Provider } from 'react-redux';
    import store from './stores';
    import requireAuth from './components/authentication/authComponent'
    import SearchComponent from './components/search/searchComponent'
    import LoginComponent from './components/login/loginComponent'
    import ExampleContainer from './containers/ExampleContainer'
    class App extends Component {
    state = {
     auth: true
    }


   componentDidMount() {
     if ( ! Cookies.get('auth')) {
       this.setState({auth:false });
     }
    }
    render() {
     return (
      <Provider store={store}>
       <BrowserRouter>
        <Switch>
         <Route exact path="/searchComponent" component={requireAuth(SearchComponent)} />
         <Route exact path="/login" component={LoginComponent} />
         <Route exact path="/" component={requireAuth(ExampleContainer)} />
         {!this.state.auth &&  <Redirect push to="/login"/> }
        </Switch>
       </BrowserRouter>
      </Provider>);
      }
     }
    }
    export default App;

Et voici authComponent

import React  from 'react';
import { withRouter } from 'react-router';
import * as Cookie from "js-cookie";
export default function requireAuth(Component) {
class AuthenticatedComponent extends React.Component {
 constructor(props) {
  super(props);
  this.state = {
   auth: Cookie.get('auth')
  }
 }
 componentDidMount() {
  this.checkAuth();
 }
 checkAuth() {
  const location = this.props.location;
  const redirect = location.pathname + location.search;
  if ( ! Cookie.get('auth')) {
   this.props.history.push(`/login?redirect=${redirect}`);
  }
 }
render() {
  return Cookie.get('auth')
   ? <Component { ...this.props } />
   : null;
  }
 }
 return  withRouter(AuthenticatedComponent)
}

Ci-dessous, j'ai écrit un blog, vous pouvez également obtenir des explications plus approfondies.

Créer des routes protégées dans ReactJS

nirmal
la source
0

La solution qui a finalement fonctionné le mieux pour mon organisation est détaillée ci-dessous, elle ajoute simplement une vérification du rendu pour la route sysadmin et redirige l'utilisateur vers un chemin principal différent de l'application s'il n'est pas autorisé à être dans la page.

SysAdminRoute.tsx

import React from 'react';
import { Route, Redirect, RouteProps } from 'react-router-dom';
import AuthService from '../services/AuthService';
import { appSectionPageUrls } from './appSectionPageUrls';
interface IProps extends RouteProps {}
export const SysAdminRoute = (props: IProps) => {
    var authService = new AuthService();
    if (!authService.getIsSysAdmin()) { //example
        authService.logout();
        return (<Redirect to={{
            pathname: appSectionPageUrls.site //front-facing
        }} />);
    }
    return (<Route {...props} />);
}

Il existe 3 routes principales pour notre implémentation, le / site public, le client / application connecté et les outils d'administration système à / sysadmin. Vous êtes redirigé en fonction de votre «authenticité» et voici la page / sysadmin.

SysAdminNav.tsx

<Switch>
    <SysAdminRoute exact path={sysadminUrls.someSysAdminUrl} render={() => <SomeSysAdminUrl/> } />
    //etc
</Switch>
C Bauer
la source