我的项目的身份验证流程是:AuthProvider 封装了所有路由,AuthProvider 具有 useEffect,它会调用 verifyToken API 来检查令牌的有效性。当用户提交登录表单时,令牌就会被发送到...
我的项目的身份验证流程是:AuthProvider 封装了所有路由,AuthProvider 具有 useEffect,它调用 verifyToken API 来检查令牌的有效性。当用户提交登录表单时,从后端设置令牌,并且页面导航到受保护的路由:受保护的路由从 AuthProvider 获取身份验证,检查令牌是否有效。
我的问题是,在用户登录之前,AuthProvider 调用 API 并且所有内容都设置为 false。因此,导航到受保护的路由会发送回登录。我必须手动输入域/仪表板来强制重新渲染所有内容,以便 AuthProvider 再次将真正的有效数据发送到受保护的路由。
这是我的AuthProvier:
import { useVerifyToken } from "@/Auth/hooks/useAuthQuery";
import { ReactNode, useEffect, useState } from "react";
import { AuthContext } from "../hooks/AuthContext";
interface AuthProviderProps {
children: ReactNode;
}
export const AuthProvider = ({ children }: AuthProviderProps) => {
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const { data: validUserDetails, isLoading:verifyTokenLoading, isSuccess, isError } = useVerifyToken();
useEffect(() => {
if (validUserDetails && isSuccess) {
setIsAuthenticated(true);
sessionStorage.setItem('validUserDetails', JSON.stringify(validUserDetails));
}
else if (isError) {
setIsAuthenticated(false);
sessionStorage.removeItem('validUserDetails');
}
}, [validUserDetails, isSuccess, isError])
console.trace(isAuthenticated)
return (
<AuthContext.Provider value={{isAuthenticated,verifyTokenLoading}}>
{children}
</AuthContext.Provider>
)
}
这是AuthContext:
import { createContext } from "react";
interface AuthContextValue {
isAuthenticated: boolean;
verifyTokenLoading: boolean;
}
export const AuthContext = createContext<AuthContextValue>({
isAuthenticated: false,
verifyTokenLoading: false,
});
这是 ProtectedRoute 组件:
import Sidebar from "@/Common/pages/Sidebar"
import { Navigate, Outlet } from "react-router-dom"
import Spinner from '@/Common/Utils/Spinner'
import { useContext } from "react"
import { AuthContext } from "@/Common/hooks/AuthContext";
function ProtectedRoute() {
const {isAuthenticated,verifyTokenLoading} =useContext(AuthContext);
if (verifyTokenLoading) {
return (
<Spinner />
)
}
if (!isAuthenticated) {
return <Navigate to={'/auth/login'} replace />
}
return (
<section className="flex">
<section className="w-[23%] min-h-screen">
<Sidebar />
</section>
<section className="w-full px-4 py-4 bg-tertiary/5 min-h-screen">
<Outlet />
</section>
</section>
)
}
export default ProtectedRoute
这是我的路线:
import {createBrowserRouter, Navigate} from 'react-router-dom';
import App from './App';
import Auth from './Auth/views/Index';
import LoginForm from './Auth/components/LoginForm';
import SignupForm from './Auth/components/SignupForm';
import ForgetPassword from './Auth/components/ForgetPassword';
import NotFoundPage from './Common/pages/NotFoundPage';
import ErrorPage from './Common/pages/ErrorPage';
import ProtectedRoute from './Auth/components/ProtectedRoute';
import Dashboard from '@/Dashboard/views/Index';
import MyProjects from '@/MyProjects/views/Index';
import Calendar from '@/Calendar/views/Index';
export const routes=createBrowserRouter([
{
path:'',
element:<App/>,
children:[
{
path:'auth',
element:<Auth/>,
children:[
{
path:'',
element:<Navigate to={'/auth/login'} replace/>
},
{
path:'login',
index:true,
element:<LoginForm/>
},
{
path:'signup',
element:<SignupForm/>
},
{
path:'forgetpassword',
element:<ForgetPassword/>
}
]
},
{
path:'',
element:<ProtectedRoute/>,
children:[
{
index:true,
element:<Navigate to={'/dashboard'}/>
},
{
path:'dashboard',
element:<Dashboard/>
},
{
path:'myprojects',
element:<MyProjects/>
},
{
path:'calendar',
element:<Calendar/>
}
]
}
],
errorElement:<ErrorPage/>
},
{
path:'*',
element:<NotFoundPage/>
}
])
这是我使用反应查询的 APICalls:
import { ApiManager } from "@/Common/Services/TaskItApi/ApiManager";
import { AuthEndpoints } from "@/Common/Services/TaskItApi/Endpoints";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { SignUp } from "../components/SignupForm";
import { LoginData } from "../components/LoginForm";
import { toast } from "sonner";
export const useSignUp = () => {
return useMutation({
mutationFn: async (data:SignUp) => {
const response = await ApiManager.post(AuthEndpoints.signUp(), data);
return response;
},
onError:(error)=>{
toast.error(error.message)
},
onSuccess:()=>{
toast.success('Account Registered Successfully')
}
});
};
export const useLogin = () => {
const queryClient=useQueryClient();
return useMutation({
mutationFn: async (data:LoginData) => {
queryClient.invalidateQueries({queryKey:['validUserDetails']})
const response = await ApiManager.post(AuthEndpoints.login(), data);
return response;
},
onError:(error)=>{
toast.error(error.message)
}
});
};
export const useVerifyToken=()=>{
return useQuery({
queryKey:['validUserDetails'],
queryFn:async()=>{
const response =await ApiManager.get(AuthEndpoints.verifyToken());
return response;
},
retry:0,
})
}
export const useLogout=()=>{
const queryClient=useQueryClient();
return useMutation({
mutationFn:async()=>{
const response=await ApiManager.post(AuthEndpoints.logout(),{});
return response;
},
onSuccess:()=>{
queryClient.invalidateQueries({queryKey:['validUserDetails']})
toast.success('Logout Successful')
},
onError:(error)=>{
toast.error(error.message)
}
})
}
我可以尝试,根据更改的令牌强制重新渲染 AuthProvider。但我也找不到这样做的方法。