状态数据持久化和代币丢失问题

问题描述 投票:0回答:1

我正在尝试使用 JWT 私有化一些路由,当登录数据保存在 AuthProvider 的状态时一切都很好,因为它与令牌相对应,但是当我重新加载页面时,数据保存在“子字段”中状态和用户令牌以某种方式丢失。这给我带来了问题,因为当页面重新加载时,它会再次重定向到登录(公共路径),只要用户未登录,这就是正确的。

验证提供者

import { useState, useEffect, createContext } from "react";
import clientAxios from "../config/ClientAxios";
import { useNavigate } from "react-router-dom";

const AuthContext = createContext();

const AuthProvider = ({ children }) => {
  const [auth, setAuth] = useState({});

  const navigate = useNavigate();
  
  useEffect(() => {
    const authUser = async () => {
      const token = localStorage.getItem("token");
      
      if (!token) {
    
        
        return;
      }
      const config = {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
      };
      try {
        const data = await clientAxios("/usuarios/perfil", config);
        setAuth(data);
        navigate('/inicio')
        
      } catch (error) {
        
        setAuth({});
      }
    };

    authUser();
  }, []);

  return (
    <AuthContext.Provider
      value={{
        auth,
        setAuth,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
};
export { AuthProvider };

export default AuthContext;

受保护的路线

import React from "react";
import { Outlet, Navigate } from "react-router-dom";
import useAuth from "../hooks/useAuth";
import Header from "../components/Header";

const ProtectedRoute = () => {

  const { auth } = useAuth();

  return(
    <div>
      
       {auth._id ? (
        <div className="bg-gray-100">
          <Header/>
          <div className="md:min-h-screen">
            <main>
             <Outlet/>
            </main>
            
          </div>
        </div>
       )
       :<Navigate to="/"/> }
      
    </div>
  ) 
};

export default ProtectedRoute;

使用验证

import { useContext } from "react";
import AuthContext from "../context/AuthProvider";

const useAuth = () => {
  return useContext(AuthContext);
};

export default useAuth;

登录

    import { Link, useNavigate } from "react-router-dom";
import { useState } from "react";
import Alert from "../components/Alert";
import clientAxios from "../config/ClientAxios";
import useAuth from "../hooks/useAuth";
import { AuthProvider } from "../context/AuthProvider";

const Login = () => {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [alert, setAlert] = useState({});

  const {setAuth}=useAuth()


  const navigate=useNavigate()

  const handleSubmit = async (e) => {
    e.preventDefault();
    if ([email, password].includes("")) {
      setAlert({
        msg: "Hay uno o mas campos vacios",
        error: true,
      });
      return;
    
    }
    try {
      const {data}=await clientAxios.post('/usuarios/',{email,password})
      setAlert({})
      localStorage.setItem('token',data.token)
      setAuth(data)
      navigate('/inicio')
    } catch (error) {
      setAlert({
        msg:error.response.data.msg,
        error:true
      })
    }
  };

  const { msg } = alert;
  return (
    <div>
      <h1 className="text-sky-600 font-black text-4xl capitalize mt-3">
        Bienvenido de vuelta !
      </h1>
      <h3 className="text-gray-400 text-xl font-black">
        {" "}
        Inicia sesion y mejora tu
        <span className="text-sky-500"> ambiente laboral</span>
      </h3>

      {msg && <Alert alert={alert} />}
      <form onSubmit={handleSubmit} className="my-5">
        <label
          htmlFor="email"
          className=" font-bold uppercase block text-xl text-gray-600"
        >
          Email
        </label>
        <input
          id="email"
          type="email"
          value={email}
          onChange={(e) => setEmail(e.target.value)}
          placeholder="Email Laboral"
          className="w-full mt-3 p-3 border rounded-xl bg-gray-200 cursor-pointer"
        />
        <label
          htmlFor="password"
          className=" font-bold uppercase block text-xl text-gray-600 mt-3"
        >
          Contraseña
        </label>
        <input
          id="password"
          type="password"
          value={password}
          onChange={(e) => setPassword(e.target.value)}
          placeholder="Contraseña"
          className="w-full mt-3 p-3 border rounded-xl bg-gray-200 cursor-pointer"
        />

        <input
          type="submit"
          value="Iniciar Sesion"
          className="bg-sky-700 text-white w-full py-3 mt-5 font-bold rounded-md uppercase hover:cursor-pointer hover:bg-sky-900 transition-colors"
        />
      </form>
      <nav>
        <Link
          className="hover:underline block text-center my-5 text-slate-500 font-semibold uppercase text-sm"
          to="forget-password"
        >
          Cambia tu Contraseña
        </Link>
      </nav>
    </div>
  );
};

export default Login;

This is what should persist even when you reload the page. This happens every time you login.

This happens when I reload the page and it returns me to my Login. It does not help me to save the data in the State's data hood because I can not access and verify from ProtectedRoute that there is an id because it verifies directly from the State.

正常流程应该是,当页面重新加载时,用户的数据和令牌都不会丢失,因为这是在其他私有路由中执行其他操作所必需的。

javascript reactjs react-hooks jwt local-storage
1个回答
0
投票

您的受保护路由需要知道您是否仍在加载身份验证,您可以尝试类似的操作

const AuthProvider = ({ children }) => {
  const [auth, setAuth] = useState({});
  const [isLoading, setIsLoading] = useState(true); // start of with loading as true
  const navigate = useNavigate();
  
  useEffect(() => {
    const authUser = async () => {
      const token = localStorage.getItem("token");
      
      if (!token) {
        setIsLoading(false); // set to false on early exit

        return;
      }

      const config = {
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${token}`,
        },
      };

      try {
        const data = await clientAxios("/usuarios/perfil", config);
        setAuth(data);
        navigate('/inicio')
        
      } catch (error) {
        
        setAuth({});
      } finally {
        setIsLoading(false); // set isLoading to false after your async logic is done
      }
    };

    authUser();
  }, []);

  return (
    <AuthContext.Provider
      value={{
        auth,
        setAuth,
        isLoading,
      }}
    >
      {children}
    </AuthContext.Provider>
  );
const ProtectedRoute = () => {

  const { auth, isLoading } = useAuth();
  
  if (isLoading) { // don't do any redirects while loading, just wait
    return <div>authenticating...</div>;
  }

  return(
    <div>
      
       {auth._id ? (
        <div className="bg-gray-100">
          <Header/>
          <div className="md:min-h-screen">
            <main>
             <Outlet/>
            </main>
            
          </div>
        </div>
       )
       :<Navigate to="/"/> }
      
    </div>
  ) 
};
© www.soinside.com 2019 - 2024. All rights reserved.