grahan
grahan

Reputation: 2408

React Router Authentication Redirection

I am currently implementing an authentication/login flow with React and React Router V4. But I am struggling to find a working redirect "schema" to implement my idea.

The situation is as follows:

  1. If a user is not logged in to my system he/she should get redirect to "/login", and a specific login page component is rendered. This should be a requirement of the system, so that I can share register and login links for my application.
  2. If the user is logged in he/should should be redirected to the route the user originally wants to visit.

My current implementation:

Entry Component

export default class Entry extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    return (
        <Router>
          <Routes />
        </Router>
    );
  }
}

Routes Component (authentication checking takes place here)

class Routes extends PureComponent {

  componentDidMount() {
    this.props.loadUser(); // async method (redux) loads the actual logged in user
  }
  render() {
    return (
      <Switch>
        <Route path="/login" render={() => (!this.props.user.username ? <LoginPage {...this.props}/> : <Redirect to="/app" />)} />
        <Route path="/app" render={() => (this.props.user.username ? <AppPage {...this.props} /> : <Redirect to="/login" />)} />
        <Route exact path="/" render={props => <Redirect to="/app" />} />
      </Switch>
    );
  }
}
export default Routes;

App component (nested routing here)

export default class App extends React.Component {
  constructor(props) {
    super(props);
  }

  render() {
    const { match, user, logout } = this.props;
    return (
      <Switch>
         <Route path={`${match.path}/about`} component={About} />
         <Route path={`${match.path}`} component={Home} />
      </Switch>
    );
  }
}

The Problem now occurs when the following is happening:

  1. The user is logged in but has closed the tab of my application
  2. The user now wants to visit /app/about
  3. The routes component is loading but this.props.user.username is null
  4. User gets redirected to /login
  5. Now the async method this.props.loadUser() has updated the redux store and this.props.user.username is not null anymore and then the user gets redirected to /app but he originally wanted to visit /app/about.

So the line which makes me headaches is

<Route path="/login" render={() => (!this.props.user.username ? <LoginPage {...this.props}/> : <Redirect to="/app" />)} />

How should I handle this specific approach so that the user gets redirected to the URL he/she originally wanted to visit ?

Maybe my overall approach is a little bit weird.

Thanks in advance, I appreciate every help :)

Upvotes: 4

Views: 11534

Answers (1)

Jo&#227;o Cunha
Jo&#227;o Cunha

Reputation: 10307

Since you're using react-router v4 I recommend going to their great docs about this topic. Here

const PrivateRoute = ({ component: Component, ...rest }) => (
  <Route {...rest} render={props => (
    fakeAuth.isAuthenticated ? (
      <Component {...props}/>
    ) : (
      <Redirect to={{
        pathname: '/login',
        state: { from: props.location }
      }}/>
    )
  )}/>
)

const AuthExample = () => (
  <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>
);

Upvotes: 11

Related Questions