Home > Blockchain >  React router v6: Protected Routes displaying after logging out
React router v6: Protected Routes displaying after logging out

Time:11-07

I am attempting to implement a private route in React; the homepage should not be visible until the user logs in. If I restart my frontend, all protected routes are not accessible until the user logs in. However, after the first login, all protected routes don't seem to be protected; I can logout, the session is destroyed in my database and my backend sends a response of {isLoggedIn: false}, but for some reason I can still access the protected routes.

When I didn't use 'useState', I could login and my backend would confirm I was logged in, but I still couldn't access any protected routes. This is the closest I've got to my end goal, but obviously still doesn't work. Any help would be appreciated.

Private Routes

import { useState, useEffect } from 'react';
import React from 'react';
import axios from 'axios';

const checkIfLogged = async () => {

    let[logged, setLogged] = useState(false);

    await axios.get("http://localhost:3001/auth", { 
        withCredentials: true
    }).then((res) => {
        setLogged(res.data.isLoggedIn);
    })
    return logged;
}

const updateAuth = async(check) => {
    const loggedIn = await check;
    return loggedIn;
}

const PrivateRoutes = () =>{
    const loggedIn = updateAuth(checkIfLogged);

    return(
         loggedIn ? <Outlet /> : <Navigate to="/login" />
    )
}

export default PrivateRoutes;

Auth Check

app.get("/auth", (req, res) => {
    if(req.session.isAuth){
        res.send({isLoggedIn: true})
    }
    else{
        res.send({isLoggedIn: false})
    }
})

App.js

import{
  Routes,
  Route,
} from "react-router-dom";

import React from "react";

import Home from "./screens/Home";
import About from "./screens/About";
import Login from "./screens/Login";
import Register from "./screens/Register";
import Logout from "./screens/Logout";
import PrivateRoutes from "./utils/private";

const App = () => {
  return (
      <>
        <Routes>
          <Route element={<PrivateRoutes/>}>
            <Route path="/" exact element={<Home />}/>
            <Route path="/about" element={<About />}/>
          </Route>
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />}/>
          <Route path="/logout" element={<Logout />}/>
        </Routes>
      </>
  );
}

export default App;

CodePudding user response:

Another solution is by actually make a conditional rendering based on if the user is admin, then the page is rendered, otherwise a null is returned:

so in your PrivateRoutes:

import { useState, useEffect } from 'react';
import React from 'react';
import axios from 'axios';

const PrivateRoute = async () => {

    let[logged, setLogged] = useState(false);
    let [isSuperUser,setIsSuperUser] = useState(false) // adding new state

    useEffect(()=>{
    axios.get("http://localhost:3001/auth", { 
        withCredentials: true
    }).then((res) => {
        setLogged(res.data.isLoggedIn);
        setIsSuperUser(res.data.isSuperUser)
    })
},[isLoggedIn]) 
    return (
          isLoggedIn&& isSuperUser?<Outlet/>:null
)


}


export default PrivateRoutes;

CodePudding user response:

Edit: this solution is valid, however, I added a 2nd solution that match the OP style.

First of all, checkLoggedIn is a component, so it need to be capitalized, fix it to CheckLoggedIn

Second of all, I am not sure what backend you are using, but I would check if the user is an admin/superuser all in App.js, since we are dealing with routes here, and then based on that I will let them access the protected route:

in App.js


import{
  Routes,
  Route,
} from "react-router-dom";

import React from "react";

import {useEffect,useState} from React;
import Home from "./screens/Home";
import About from "./screens/About";
import Login from "./screens/Login";
import Register from "./screens/Register";
import Logout from "./screens/Logout";
import PrivateRoutes from "./utils/private";

const App = () => {
  let[logged, setLogged] = useState(false)
   let [isSuperUser,setIsSuperUser] = useState(false)
  useEffect(()=>{
    axios.get('localhost:3001/auth/',{withCredentials:true}).then((res)=>{
      // send a response if the current logged in user is a super user
      setLogged(res.data.isLoggedIn)
      setIsSuperUser(res.data.isSuperUser)
}
},[logged]) // useEffect will get re-invoked whenever the user log out, or their session is ended

// now for the last part, I would make a conditional rendering, where a user will access route only if they are superuser/admin
  return (
      <>
        <Routes>
          <Route element={isSuperUser?<PrivateRoutes/>:''}>
            <Route path="/" exact element={<Home />}/>
            <Route path="/about" element={<About />}/>
          </Route>
          <Route path="/login" element={<Login />} />
          <Route path="/register" element={<Register />}/>
          <Route path="/logout" element={<Logout />}/>
        </Routes>
      </>
  );
}

export default App;

Notice the first route, you will only be able to access it if you are a logged in admin.

you also need to notice that what define a react component is 2 things:

  1. Capitalization of your functional component name
  2. it has to return a JSX
  • Related