52

My App looks like:

class App extends Component {
  render() {
    <Router>
      <div>
      <Route exact path='/login' component={Login} />
      <Route exact path='/game' component={GameContainer} />
      <Route exact path='/chat' component={ChatContainer} />
      <Route exact path='/info' component={InfoContainer} />
    </div>
    </Router>  
  }

If the user visits a page under /game and is not logged in, I want to redirect them to the login page.

How to do it an elegant way in all routers?

Ivan Hreskiv
  • 797
  • 1
  • 9
  • 15
  • Add a onEnter =()={} prop to each route that will take care of authentication. There you write the authentication logic. onEnter: (nextState, replace) => { //do the authentication logic here } For react router 4 use life cycle methods . – simbathesailor Nov 24 '17 at 15:29
  • 1
    I use this code to every page that wants to authenticate and work very well: if (!this.props.isLoggedIn) { return } else{ return //default page code ... } And I can use it in login page if the user is already logged in don't display the login page again – mkareshky Aug 20 '20 at 07:38

1 Answers1

100

See this answer https://stackoverflow.com/a/43171515/208079. Perhaps someone with more rep than me can mark this as a duplicate.

The basic idea is to wrap routes that require authentication with a custom component (PrivateRoute in the example below). PrivateRoute will use some logic to determine if the user is authenticated and then either; allow the requested route to render, or redirect to the login page.

This is also described in the react-router training docs at this link https://reacttraining.com/react-router/web/example/auth-workflow.

Here is an implementation using the above as inspiration.

In App.js (or where your routing is happening)

import React, { Component } from 'react'
import { BrowserRouter as Router, Route } from 'react-router-dom'
import PrivateRoute from './PrivateRoute'
import MyComponent from '../src/MyComponent'
import MyLoginForm from '../src/MyLoginForm'

<Router>
  <Route path="/login" component={MyLoginForm} />
  <PrivateRoute path="/onlyAuthorizedAllowedHere/" component={MyComponent} />
</Router>

And the PrivateRoute Component

// This is used to determine if a user is authenticated and
// if they are allowed to visit the page they navigated to.

// If they are: they proceed to the page
// If not: they are redirected to the login page.
import React from 'react'
import AuthService from './Services/AuthService'
import { Redirect, Route } from 'react-router-dom'

const PrivateRoute = ({ component: Component, ...rest }) => {

  // Add your own authentication on the below line.
  const isLoggedIn = AuthService.isLoggedIn()

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

export default PrivateRoute
bluesixty
  • 1,977
  • 3
  • 16
  • 19
  • if we are using object of routes then how can we create a protected route. const routes = { path: '/', childRoutes: [ { path: '/login', component: Login}, { path: '/transaction', component: Transaction, }, { path: '*', component: PageNotFound } ] } – ngLover Mar 13 '18 at 12:37
  • Out of curiosity has anyone come up with a clean way to do the _reverse_ of what OP is asking? i.e. how to declare a route like `/login` that is _only accessible_ if the user is NOT logged in/authenticated? – mecampbellsoup Mar 17 '21 at 21:50