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

React V6中ProtectedRoutes无法保护/auth路径,请求排查解决

问题:React Router V6中ProtectedRoutes无法正确保护/auth路径

在React Router V6中使用ProtectedRoutes组件保护/auth路径,但未登录状态下仍能直接访问该页面,确认问题与V5到V6的路由变更相关,相关代码如下:

index.js

import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';
import 'bootstrap/dist/css/bootstrap.min.css';
import { BrowserRouter } from "react-router-dom";


const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
  <BrowserRouter>
    <App />
  </BrowserRouter>  
  </React.StrictMode>
);

App.js

import { Routes, Route } from "react-router-dom";
import { Container, Col, Row } from "react-bootstrap";
import Account from "./Account";
import FreeComponent from "./FreeComponent";
import AuthComponent from "./AuthComponent";
import ProtectedRoutes from "./ProtectedRoutes";


function App() {
  return (
    <Container>
      <Row>
        <Col className="text-center">
          <h1>React Authentication Tutorial</h1>
          <section id="navigation">
            <a href="/">Home </a>
            <a href="/free">Free Component </a>
            <a href="/auth">Auth Component </a>
          </section>
        </Col>
      </Row>
      <Routes>
        <Route exact path="/" element={<Account />} />
        <Route exact path="/free" element={<FreeComponent />} />
        <Route element={<ProtectedRoutes />}>
          <Route exact path="/auth" element={<AuthComponent/>}/>
        </Route>
      </Routes>
    </Container>
  );
}

export default App;

ProtectedRoutes.js

import React from 'react'
import {Navigate, Outlet} from 'react-router-dom';
import Cookies from "universal-cookie";
const cookies = new Cookies();


const useAuth=()=>{
  const token = cookies.get("TOKEN");
  if(token){
    return true
  } else {
    return false
  }
}

const ProtectedRoutes=(props:any) =>{
  const auth=useAuth()
  return auth?<Outlet/>: <Navigate to="/"/>
}

export default ProtectedRoutes;

AuthComponent.js

import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import axios from "axios";
import Cookies from "universal-cookie";
const cookies = new Cookies();

const token = cookies.get("TOKEN");

export default function AuthComponent() {
  const [message, setMessage] = useState("");

  useEffect(() => {
    const configuration = {
      method: "get",
      url: "https://myurl.com/auth-endpoint",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };

    axios(configuration)
      .then((result) => {
        setMessage(result.data.message);
      })
      .catch((error) => {
        error = new Error();
      });
  }, []);

  const logout = () => {
    cookies.remove("TOKEN", { path: "/" });
    window.location.href = "/";
  }

  return (
    <div className="text-center">
      <h1>Auth Component</h1>
      <h3 className="text-danger">{message}</h3>
      <Button type="submit" variant="danger" onClick={() => logout()}>
        Logout
      </Button>
    </div>
  );
}

问题表现:访问http://localhost:3000/auth时无需登录即可查看页面,需实现登录后才能访问该路径的效果。


解决方案

1. 修正useAuth为符合规范的自定义Hook

原来的useAuth是普通函数,未遵循React Hook规则,导致组件无法在认证状态变化时重新渲染。修改后确保它是合法的自定义Hook:

修改后的ProtectedRoutes.js:

import React from 'react'
import { Navigate, Outlet } from 'react-router-dom';
import Cookies from "universal-cookie";

// 自定义Hook必须以use开头,符合React Hook规则
const useAuth = () => {
  const cookies = new Cookies();
  const token = cookies.get("TOKEN");
  // 用!!将token转换为布尔值,避免空字符串、null等被误判为有效
  return !!token;
}

const ProtectedRoutes = () => {
  const isAuthenticated = useAuth();

  // 使用replace属性,避免用户通过后退按钮回到/auth页面
  return isAuthenticated ? <Outlet /> : <Navigate to="/" replace />;
}

export default ProtectedRoutes;

2. 增强AuthComponent的认证校验

在AuthComponent初始化时主动校验token有效性,处理token不存在或过期的情况:

修改后的AuthComponent.js:

import React, { useEffect, useState } from "react";
import { Button } from "react-bootstrap";
import axios from "axios";
import Cookies from "universal-cookie";

export default function AuthComponent() {
  const [message, setMessage] = useState("");
  const cookies = new Cookies();

  useEffect(() => {
    const token = cookies.get("TOKEN");
    // 先检查本地token是否存在,不存在直接跳转登录页
    if (!token) {
      window.location.href = "/";
      return;
    }

    const configuration = {
      method: "get",
      url: "https://myurl.com/auth-endpoint",
      headers: {
        Authorization: `Bearer ${token}`,
      },
    };

    axios(configuration)
      .then((result) => {
        setMessage(result.data.message);
      })
      .catch((error) => {
        // API请求失败(如token过期),清除无效token并跳转登录页
        cookies.remove("TOKEN", { path: "/" });
        window.location.href = "/";
      });
  }, []);

  const logout = () => {
    cookies.remove("TOKEN", { path: "/" });
    window.location.href = "/";
  }

  return (
    <div className="text-center">
      <h1>Auth Component</h1>
      <h3 className="text-danger">{message}</h3>
      <Button type="submit" variant="danger" onClick={logout}>
        Logout
      </Button>
    </div>
  );
}

3. 优化App.js的路由写法

React Router V6中exact属性已被移除(路由默认精确匹配),可以删除所有exact属性,让代码更简洁:

修改后的App.js路由部分:

<Routes>
  <Route path="/" element={<Account />} />
  <Route path="/free" element={<FreeComponent />} />
  <Route element={<ProtectedRoutes />}>
    <Route path="/auth" element={<AuthComponent/>}/>
  </Route>
</Routes>

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 11:02:07