Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to restrict access to routes in react-router?

Does anyone know how to restrict access to particular routes in react-router? I want to check if the user is logged in before allowing access to a particular route. I thought it would be simple, but the docs aren't clear how to do it.

Is this something I should set up where I define my <Route> components, or should I be handling it inside my component handlers?

<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> 
like image 963
Tanner Semerad Avatar asked Jun 27 '15 03:06

Tanner Semerad


People also ask

How do I restrict access to Route react?

The Route component from react-router is public by default but we can build upon it to make it restricted. We can add a restricted prop with a default value of false and use the condition if the user is authenticated and the route is restricted, then we redirect the user back to the Dashboard component.

How do I protect routes in react v6 router?

import { Navigate } from "react-router-dom"; import { useAuth } from "../hooks/useAuth"; export const ProtectedRoute = ({ children }) => { const { user } = useAuth(); if (!user) { // user is not authenticated return <Navigate to="/" />; } return children; }; To redirect the user, we use the <Navigate /> component.

How do I create a private route in react?

Path: /src/_components/PrivateRoute.jsx The react private route component renders child components ( children ) if the user is logged in. If not logged in the user is redirected to the /login page with the return url passed in the location state property.


1 Answers

Update (Aug 16, 2019)

In react-router v4 and using React Hooks this looks a little different. Let's start with your 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>   ); } 

We are using an Auth library to check if the user is currently authenticated. Replace this with your auth check function. If so then we set the isAuthenticated flag to true. We do this when our App first loads. Also worth mentioning, you might want to add a loading sign on your app while the auth check is being run, so you don't flash the login page every time you refresh the page.

Then we pass the flag to our routes. We create two type of routes AuthenticatedRoute and UnauthenticatedRoute.

The AuthenticatedRoute.js looks like this.

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}`}             />}     />   ); } 

It checks if isAuthenticated is set to true. If it is, then it'll render the desired component. If not, then it'll redirect to the login page.

The UnauthenticatedRoute.js on the other hand looks like this.

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

In this case, if the isAuthenticated is set to false, it'll render the desired component. And if it is set to true, it'll send you to the homepage.

You can find detailed versions of this on our guide - https://serverless-stack.com/chapters/create-a-route-that-redirects.html.

Older version

The accepted answer is correct but Mixins are considered to be harmful (https://facebook.github.io/react/blog/2016/07/13/mixins-considered-harmful.html) by the React team.

If somebody comes across this question and is looking for the recommended way to do this, I'd suggest using Higher Order Components instead of Mixins.

Here is an example of a HOC that'll check if the user is logged in before proceeding. And if the user is not logged in, then it'll redirect you to the login page. This component takes a prop called isLoggedIn, that is basically a flag that your application can store to denote if the user is logged in.

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); } 

And to use this HOC, just wrap it around your routes. In case of your example, it would be:

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

I cover this and a few other topics in a detailed step-by-step tutorial here - https://serverless-stack.com/chapters/create-a-hoc-that-checks-auth.html

like image 71
jayair Avatar answered Sep 23 '22 04:09

jayair