You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React私有路由无法识别已登录状态问题求助

已登录用户访问/login路径时,AuthContext的isAuthenticated始终为false的问题

我使用React Context存储已登录用户的信息:

import React, { createContext, Dispatch, SetStateAction, useEffect, useState } from "react";

interface User {
    name?: string;
    email?: string;
    rating?: number;
}

interface LoggedUserInterface {
    isAuthenticated: boolean;
    user: User;
}

interface IAuthContext extends LoggedUserInterface {
    setLoggedUser: Dispatch<SetStateAction<IAuthContext>>;
}

type Props = {
    children?: React.ReactNode;
};
// Default value for IAuthContext
const defaultAuthContextValue: IAuthContext = {
    isAuthenticated: false,
    user: {
        name: undefined,
        email: undefined,
        rating: undefined,
    },
    setLoggedUser: () => {}, // You might want to provide a default implementation
};

const AuthContext = createContext<IAuthContext>(defaultAuthContextValue);

const AuthProvider: React.FC<Props> = ({ children }) => {
    const [loggedUser, setLoggedUser] = useState<IAuthContext>(defaultAuthContextValue);

    useEffect(() => {
        async function getWhoAmI() {
            try {
                const response = await fetch("http://localhost:8080/api/v1/profile/status", {
                    method: "GET",
                    credentials: "include",
                });

                if (response.ok) {
                    const data = await response.json();
                    setLoggedUser((prev) => ({ ...prev, isAuthenticated: data.isAuthenticated, user: data }));
                } else {
                    setLoggedUser((prev) => ({ ...prev, isAuthenticated: false, user: {} }));
                    console.error("Error checking authentication status:", response.statusText);
                }
            } catch (error: any) {
                setLoggedUser((prev) => ({ ...prev, isAuthenticated: false, user: {} }));
                console.error("Error checking authentication status:", error.message);
            }
        }

        getWhoAmI();
    }, []);

    return (
        <AuthContext.Provider value={{ ...loggedUser, setLoggedUser }}>
            {children}
        </AuthContext.Provider>
    );
};

export { AuthContext, AuthProvider };

我还有一个登录页面,希望阻止已登录用户访问/login路径:

import React, {useContext, useEffect, useState} from 'react';
import {Button, Paper, TextField, Typography} from '@mui/material';
import {useNavigate} from 'react-router-dom';
import './Login.css';
import {AuthContext} from "../context/AuthContext";

const Login: React.FC = () => {
    const [formData, setFormData] = useState({
        email: '',
        password: '',
    });

    const navigate = useNavigate();
    const authContext = useContext(AuthContext);
    const {setLoggedUser} = authContext;

    const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
        const {name, value} = event.target;
        setFormData((prevFormData) => ({
            ...prevFormData,
            [name]: value,
        }));
    };

    const loginUser = async () => {
        const endpoint = 'http://localhost:8080/api/v1/auth/login';

        try {
            const response = await fetch(endpoint, {
                method: 'POST',
                credentials: 'include',
                headers: {
                    'Content-Type': 'application/json',
                },
                body: JSON.stringify(formData),
            });

            if (response.ok) {
                const data = await response.json();
                setLoggedUser({
                    ...authContext,
                    isAuthenticated: true,
                    user: {
                        name: data.name,
                        email: data.email,
                        rating: data.rating,
                    },
                });
                // Redirect to the desired page upon successful login
                navigate('/');
            } else {
                const errorData = await response.json();
                console.error('Login failed:', errorData.message);
            }
        } catch (error: any) {
            console.error('Error during login:', error.message);
            console.log(error);
        }
    };

    const handleSubmit = () => {
        loginUser();
    };
    
    return (
        <>
            <div id="login-wrapper">
                <Paper elevation={3} id="login-container">
                    <Typography variant="h2" align="center" gutterBottom>
                        Login
                    </Typography>
                    <form style={{display: 'flex', flexDirection: 'column', gap: '16px', width: '100%'}}>
                        <TextField label="Email" type="email" variant="outlined" onChange={handleInputChange}
                                   name="email"/>
                        <TextField label="Password" type="password" variant="outlined" onChange={handleInputChange}
                                   name="password"/>

                        <Button variant="contained" color="primary" onClick={handleSubmit}>
                            Login
                        </Button>
                    </form>
                </Paper>
            </div>
        </>
    );
};

export default Login;

为此,我使用了私有路由:

import React, { ReactNode } from "react";
import { Navigate, Outlet } from "react-router-dom";

interface ProtectedRouteProps {
    isAllowed: boolean;
    redirectTo?: string;
    children?: ReactNode;
}

export default function ProtectedRoute({ isAllowed, redirectTo = "/", children }: ProtectedRouteProps) {
    console.log("LOGGED IS " + isAllowed)
    if (isAllowed) {
        return <Navigate to={redirectTo} />;
    }
    return children ? <> {children} </> : <Outlet />;
}

使用方式如下:

function App() {

    const authContext = useContext(AuthContext);

    return (
        <div className="container">
            <AuthProvider>
                <Header/>
                <Routes>
                    <Route path="/" element={<Home/>}/>
                    <Route path="/register" element={<Register/>}/>
                    <Route path="/login" element={
                        <ProtectedRoute isAllowed={authContext.isAuthenticated} redirectTo='/'>
                            <Login/>
                        </ProtectedRoute>}
                    />
                    <Route path="/howto" element={<HowTo/>}/>
                </Routes>
                <Footer/>
            </AuthProvider>
        </div>
    );
}

当我在登录页面登录后,会跳转到"/"页面,但当我尝试通过URL访问/login时,并未如预期跳转回"/"(此时用户已登录)。我检查条件发现,当通过URL访问/login时,authContext.isAuthenticated始终为false。

这是为什么?我的Header组件可以根据用户是否登录正确显示内容,说明Context状态并未改变。那为什么这里会是false?

感谢您的帮助!

内容的提问来源于stack exchange,提问作者Johnyb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 09:17:02