ipenguin67
ipenguin67

Reputation: 1649

How to ensure all routes contained within a protected route are also protected?

In my app, there are a number of static pages that define the "home" or "marketing" site, things like /home, /about, /pricing, etc. These routes are accessible at anytime by anybody.

Then, there is the app itself, currently living at "/". It has logic to ensure anyone who is not authenticated who tries to access "/" will be redirected to "/home".

const App = ({history, ...props}) => {
  const { isAuthenticated } = useSelector(mapState);

  useEffect(() => {
    if (!isAuthenticated) {
      history.push("/home");
    }
  },
  [isAuthenticated]
);

  return (
    <div className="App">
      <h1>You've reached My App!</h1>
      <p>Nothing to see here...YET!</p>
      <Switch>
        <Route path="/randomroute" component={ComponentWithinTheApp} />
      </Switch>
    </div>
  );
}

Within the App, there will likely need to be a whole range of other routes, for dashboard, user profile, etc. It's not practical to set up authentication hooks for each of those routes and components, so I'm wondering if there is a way to ensure that any component rendered by a that is a child of App.js is also redirected back to "/home" if the user is not authenticated.

Upvotes: 1

Views: 741

Answers (1)

Jake
Jake

Reputation: 732

I suggest you make use of some sort of privateroute component where you check for the token and then return a component if it passes or redirect upon failure like so:

import React from 'react';
import { Route, Redirect } from 'react-router-dom';
import Auth from '../../Modules/Auth';

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

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

  export default PrivateRoute;

Then in the Auth file being imported write a class that checks for the token however it may be:

class Auth {

    /**
     * Authenticate a user. Save a token string in Local Storage
     *
     * @param {string} token
     */
    static authenticateUser(token) {
      localStorage.setItem('token', token);
    }

    /**
     * Check if a user is authenticated - check if a token is saved in Local Storage
     *
     * @returns {boolean}
     */
    static isUserAuthenticated() {
      return localStorage.getItem('token') !== null;
    }

    /**
     * Deauthenticate a user. Remove a token from Local Storage.
     *
     */
    static deauthenticateUser() {
      localStorage.removeItem('token');
    }

    /**
     * Get a token value.
     *
     * @returns {string}
     */

    static getToken() {
      return localStorage.getItem('token');
    }

  }

  export default Auth;

Then in your switch you could write something like:

<Switch>
    <PrivateRoute path="/randomroute" component={ComponentWithinTheApp} />
</Switch>

Upvotes: 2

Related Questions