Home > Software design >  How to avoid unlogged users to see pages for logged in users? Next JS Client side authentication
How to avoid unlogged users to see pages for logged in users? Next JS Client side authentication

Time:05-02

I'm handling my app's authentication on client side using localStorage, and if there is not an "user" item in localStorage, then it means the person is not logged in and should be redirected to /login page.

The problem is when for example, someone is accessing the root page for the first time and is not logged in, the person will be able to see for 1 or 2 seconds the "/" main page content, which should only be seen by logged users, and THEN, the user will be redirected to "/login" for authentication.

I know why this is happening but I wonder if there is a better way to do this and avoid this annoying little problem.

Here's my login.js page code:

import React from "react";
import Image from "next/image";

import GoogleLogin from "react-google-login";
import { FcGoogle } from "react-icons/fc";

import { useRouter } from "next/router";

import axios from "axios";

const Login = () => {
  const router = useRouter();

  const apiUserLogin = async (userName, userId, userImage) => {
    try {
      axios.post(
        `/api/users/login?name=${userName}&googleId=${userId}&imageUrl=${userImage}`
      );
    } catch (error) {
      console.log(error);
    }
  };

  const responseGoogle = (response) => {
    localStorage.setItem("user", JSON.stringify(response.profileObj));

    const { name, googleId, imageUrl } = response.profileObj;

    apiUserLogin(name, googleId, imageUrl).then(() => {
      router.push("/");
    });
  };

  return (
    <div className="flex flex-col items-center justify-center h-screen bg-black">
      <video
        src="/PostItvideo2.mp4"
        type="video/mp4"
        loop
        controls={false}
        muted
        autoPlay
        className="object-cover w-full h-full brightness-50"
      />

      <div className="absolute top-0 bottom-0 left-0 right-0 flex flex-col items-center justify-center">
        <div className="p-3">
          <Image
            src="/Postit-logofull.svg"
            width={140}
            height={80}
            alt="logo"
          />
        </div>

        <GoogleLogin
          clientId={`${process.env.NEXT_PUBLIC_GOOGLE_CLIENT_ID}`}
          render={(renderProps) => (
            <button
              type="button"
              className="flex items-center justify-center px-8 py-3 text-lg font-bold text-black bg-white border-none rounded-lg outline-none cursor-pointer"
              onClick={renderProps.onClick}
            >
              <FcGoogle size={21} className="mr-2" /> Sign in with Google
            </button>
          )}
          onSuccess={responseGoogle}
          onFailure={responseGoogle}
          cookiePolicy="single_host_origin"
        />
      </div>
    </div>
  );
};

export default Login; 

This is my _app.js code, this is where the "redirect if not logged in" happens:

import React, { useEffect } from "react";
import { AppContext } from "../context/context";
import { useRouter } from "next/router";

import "../styles/globals.css";

function MyApp({ Component, pageProps }) {
  const router = useRouter();

  useEffect(() => {
    const userInfo =
      localStorage.getItem("user") !== "undefined"
        ? JSON.parse(localStorage.getItem("user"))
        : null;

    if (router.pathname !== "/login" && !userInfo) router.push("/login");
  }, []);

  return (
    <AppContext>
      <Component {...pageProps} />
    </AppContext>
  );
}

export default MyApp;

CodePudding user response:

Typically there would be a loading screen.

function MyApp({ Component, pageProps }) {
  const router = useRouter();
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    const userInfo = GET_USER_FROM_LS;
    if (router.pathname !== "/login" && !userInfo) {
     router.push("/login");
    } else {
     setIsLoading(false)
    }
  }, []);

  if(isLoading) {
   return <YourLoadingComponent />
  }

  return YOUR_DEFAULT_RETURN;
}

I personally try to keep _app clean so I'd probably put all of the login logic in AppContext.

  • Related