Home > other >  React - How to check if user is still authenticated
React - How to check if user is still authenticated

Time:01-08


I have a small app in react and I need to check if user is still authenticated after leaving the page. But my solution do not work.
I think I am doing something bad in useEffect part. Because I don't have user on first render.
Is this a good solution or it can be done in better/different way?

Thanks for any suggestions.

Login page - handle login

  const handleLogin = async (e: React.FormEvent<HTMLFormElement>) => {
    e.preventDefault();
    try {
      if (!username || !password) {
        setError('Pole musí být vyplněna!');
        return;
      }

      const userData = await axios.post(
        `${process.env.REACT_APP_BACKEND_URL}/account/login`,
        {
          username,
          password,
        }
      );

      if (!userData) {
        throw new Error();
      }

      setUser(userData.data);
      localStorage.setItem('token', userData.data.token);
      navigate(state?.path || '/home');
    } catch (err: any) {
      setError('Nesprávné jméno nebo heslo!');
    }
  };

App.ts

function App() {
  const [user, setUser] = useState<ICurrentUser>({
    name: '',
    role: '',
    username: '',
  });

  useEffect(() => {
    const checkUser = async () => {
      const token = localStorage.getItem('token');
      if (token !== null) {
        const userData = await axios.get(
          `${process.env.REACT_APP_BACKEND_URL}/account/checkToken`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );

        setUser({
          name: `${userData.data.firstname} ${userData.data.lastname}`,
          role: userData.data.role,
          username: userData.data.username,
        });
      }
    };

    checkUser().catch((err) => console.log(err));
  }, []);

  return (
    <>
      <UserContext.Provider value={{ user, setUser }}>
        <Routes>
          <Route path="/" element={<Login />}></Route>
          <Route
            path="/home"
            element={
              <ProtectedRoute>
                <HomePage />
              </ProtectedRoute>
            }
          />
          <Route
            path="stazky"
            element={
              <ProtectedRoute>
                <Stazky />
              </ProtectedRoute>
            }
          />
          <Route
            path="zamestnanci"
            element={
              <ProtectedRoute>
                <Zamestnanci />
              </ProtectedRoute>
            }
          />
          <Route
            path="newZam"
            element={
              <ProtectedRoute>
                <NovyZamestnanec action="create" />
              </ProtectedRoute>
            }
          />
          <Route
            path="zam/:id"
            element={
              <ProtectedRoute>
                <NovyZamestnanec action="edit" />
              </ProtectedRoute>
            }
          />
          <Route
            path="new"
            element={
              <ProtectedRoute>
                <NovaStazka />
              </ProtectedRoute>
            }
          />
          <Route
            path="vozidla"
            element={
              <ProtectedRoute>
                <Vozidla />
              </ProtectedRoute>
            }
          />
          <Route
            path="newVehicle"
            element={
              <ProtectedRoute>
                <NoveVozidlo />
              </ProtectedRoute>
            }
          />
          <Route
            path="*"
            element={
              <ProtectedRoute>
                <NotFound />
              </ProtectedRoute>
            }
          />
        </Routes>
      </UserContext.Provider>
    </>
  );
}

ProtectedRoute.ts

const ProtectedRoute: React.FC<IProps> = ({ children }) => {
  const location = useLocation();
  const { user } = useContext(UserContext);
  const isAuth = !!user.username;

  return isAuth ? (
    <Layout>{children}</Layout>
  ) : (
    <Navigate to="/" replace state={{ path: location.pathname }} />
  );
};

export default ProtectedRoute;

CodePudding user response:

I finaly figured out how to do it.

Only thing needed was add "loading state" to context. I`ll post my code for reference if someone else is strugling with that.

ProtectedRoute

const ProtectedRoute: React.FC<IProps> = ({ children }) => {
  const location = useLocation();
  const { user, loading } = useContext(UserContext);
  const isAuth = !!user.username;

  if (loading) {
    return <h1>Loading..</h1>;
  }

  return isAuth ? (
    <Layout>{children}</Layout>
  ) : (
    <Navigate to="/" replace state={{ path: location.pathname }} />
  );
};

App.js

function App() {
  const [user, setUser] = useState<ICurrentUser>({
    name: '',
    role: '',
    username: '',
  });
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    const checkUser = async () => {
      const token = localStorage.getItem('token');
      if (token !== null) {
        const userData = await axios.get(
          `${process.env.REACT_APP_BACKEND_URL}/account/checkToken`,
          {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          }
        );

        localStorage.setItem('token', userData.data.token);
        setUser({
          name: `${userData.data.firstname} ${userData.data.lastname}`,
          role: userData.data.role,
          username: userData.data.username,
        });

        setLoading(false);
      }
    };

    checkUser();
  }, []);

  return (
    <>
      <UserContext.Provider value={{ user, setUser, loading }}>
        <Routes>
          <Route path="/" element={<Login />}></Route>
          <Route
            path="/home"
            element={
              <ProtectedRoute>
                <HomePage />
              </ProtectedRoute>
            }
          />
          <Route
            path="stazky"
            element={
              <ProtectedRoute>
                <Stazky />
              </ProtectedRoute>
            }
          />
                   </Routes>
      </UserContext.Provider>
    </>
  );
}

Context

interface IContent {
  loading: boolean;
  user: ICurrentUser;
  setUser: (user: ICurrentUser) => void;
}

export const UserContext = createContext<IContent>({
  user: {
    name: '',
    role: '',
    username: '',
  },
  setUser: () => {},
  loading: true,
});
  •  Tags:  
  • Related