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

React实现RBAC后登录跳转页面空白问题排查

React RBAC权限控制页面空白问题排查

我正在React应用中实现RBAC(基于角色的访问控制),后端采用Node.js且运行正常,前端使用Vite + react-router-dom v6。目前将从服务器获取的token和role存储在Session Storage中,应用包含basic和admin两个角色,登录成功后会根据返回角色跳转,用HOC作为路由中间件校验权限。现在跳转功能正常,但两个角色对应的页面均显示空白(本该渲染简单文本),求排查问题。


登录页面(Login.js)

import { useState } from 'react'
import { useNavigate } from 'react-router-dom';
import axios from 'axios';

const Login = () => {
  const navigate = useNavigate()
  const [input, setInput] = useState({
    email:"",
    password:""
  })

  const handleInputChange = (e) => {
    const {name, value} = e.target;
    setInput((prev) => ({
        ...prev, [name]:value
    }))
  };

  const handleSubmit = async (e) => {
    e.preventDefault();
    console.log(input);

    const url = "http://localhost:8080/auth/login";

    try {
        const response = await axios.post(`${url}`,
        input,
        {headers:{
            'content-type':'application/json'
        }}
        );

        console.log(response);

        if(response.status === 200) {
            console.log("ok");

          const token = response.data.token;
          const role = response.data.role
          console.log({"token":token, "role":role})

          sessionStorage.setItem('token', token);
          sessionStorage.setItem('role', role);

            if(role === "admin"){
              navigate('/admin');
            } else if( role === "basic") {
              navigate('/basic');
            } else {
              navigate('/login');
            }

        }
    } catch(error) {
        console.log({"error":error.response})
    }
  }

  return (
    <div>
      <h1>Log In</h1>
        <form onSubmit={handleSubmit}>
            <p>email:</p>
            <input type="text" name="email" value={input.email} onChange={handleInputChange}/>
            <p>password:</p>
            <input type="text" name="password" value={input.password} onChange={handleInputChange}/><br/>
            <button type='submit'>Login</button>
        </form>
    </div>
  )
}

export default Login

路由布局(App.js)

import {  } from 'react'
import './App.css'
import { Route, Routes } from 'react-router'

import Access from './Auth/Access'

import Home from './pages/Home'
import Login from './pages/Login'
import Signup from './pages/Signup'
import Admin from './pages/Admin'
import Basic from './pages/Basic'
import { Error } from './pages/Error'

function App() {
  return (
    <div>
      <Routes>
        <Route path='/' element={<Home/>}/>
        <Route path='/login' element={<Login/>}/>
        <Route path='/signup' element={<Signup/>}/>
        <Route path='/basic' element={<Access role={'basic'}> <Basic/></Access>}/>
        <Route path='/admin' element={<Access role={'admin'}><Admin/></Access>}/>
        <Route path='*' element={<Error/>}/>
      </Routes>
    </div>
  )
}
export default App

权限校验HOC(Access.js)

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

const Access = ({ role }) => {
  const userRole = sessionStorage.getItem("role");
  const token = sessionStorage.getItem('token');
  
  if (!token || (role && role !== userRole)) {
    // 无token或角色不匹配时跳转到登录页
    return <Navigate to="/login" replace />;
  }

  // 权限通过,渲染嵌套组件
  return <Outlet />;
};

export default Access

Admin页面

/* eslint-disable no-unused-vars */
import React from "react"

const Admin = () => {
  return (
    <div>wecome to admin page</div>
  )
}

export default Admin

Basic页面

// eslint-disable-next-line no-unused-vars
import React from 'react'

const Basic = () => {
  return (
    <div>welcome to basic page</div>
  )
}

export default Basic

问题原因及修复

页面空白的核心原因是Access组件中Outlet的用法错误:

react-router-dom v6中,Outlet仅用于渲染嵌套路由结构的子路由内容,但你当前是直接将Basic/Admin作为Access的子元素传入,Outlet无法识别这些子元素,自然不会渲染任何内容。

修复方案(二选一)

方案1:修改Access组件,直接渲染传入的子元素

将Access组件的返回值从<Outlet />改为传入的children,适配当前路由写法:

import { Navigate } from "react-router-dom";

const Access = ({ role, children }) => {
  const userRole = sessionStorage.getItem("role");
  const token = sessionStorage.getItem('token');
  
  if (!token || (role && role !== userRole)) {
    return <Navigate to="/login" replace />;
  }

  return children;
};

export default Access

方案2:改用嵌套路由结构(符合react-router-dom v6规范)

调整App.js的路由配置,将Access作为父路由的element,页面组件作为子路由的index元素:

function App() {
  return (
    <div>
      <Routes>
        <Route path='/' element={<Home/>}/>
        <Route path='/login' element={<Login/>}/>
        <Route path='/signup' element={<Signup/>}/>
        {/* 嵌套路由方式 */}
        <Route path="/basic" element={<Access role={'basic'} />}>
          <Route index element={<Basic />} />
        </Route>
        <Route path="/admin" element={<Access role={'admin'} />}>
          <Route index element={<Admin />} />
        </Route>
        <Route path='*' element={<Error/>}/>
      </Routes>
    </div>
  )
}

此方案无需修改原Access组件,Outlet会自动渲染子路由的index元素。

另外注意:Admin页面的文本拼写错误(wecome应为welcome),但这不是页面空白的原因。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 01:04:56