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

React-Redux组件无法读取currentUser,管理员登录仍被重定向

问题背景

我的应用采用React-Redux前端 + Rails后端架构,AddCreation组件处于受保护路由下,仅登录用户可访问,路由配置如下:

function App() {
  const { authChecked, loggedIn } = useAuth();

  return (
    <Router>
      <Routes>
        <Route path="/login" element={<Login loggedIn={loggedIn} />} />
        <Route path="/signup" element={<Signup />} />
        <Route element={<ProtectedRoutes isAllowed={loggedIn} authChecked={authChecked} redirectPath="/login" />}>
          <Route path="/creations" element={<Creations />} />
          <Route path="/" element={<AddCreation />} />
        </Route>
      </Routes>
    </Router>
  );
}

AddCreation组件额外要求用户为管理员身份,否则重定向至/creations,核心逻辑如下:

useEffect(() => {
    if (currentUser.role !== 'admin') {
      navigate("/creations");
    }
  }, [currentUser.role, navigate]);

但登录后端预置的管理员用户(role=1)后,仍会被重定向至/creations。打印currentUser的用户名、角色等属性均为undefined,但登录/注册组件可正常连接后端。

后端相关代码

  1. 种子数据
user_1 = User.create(username: 'Admin User', role: 1, email: 'admin@gmail.com', password: "admin123")
  1. User模型角色枚举
enum role: %i[user admin]
after_initialize :set_default_role, if: :new_record?

def set_default_role
  self.role ||= :user
end
  1. User序列化器
class UserSerializer
  include FastJsonapi::ObjectSerializer
  attributes :id, :username, :role, :email
end
  1. 控制器返回数据处理
data: UserSerializer.new(resource).serializable_hash[:data][:attributes]

AddCreation组件核心代码(省略部分输入字段)

import React, { useEffect, useState } from 'react';
import { useSelector } from 'react-redux';
import { useForm } from 'react-hook-form';
import { useNavigate } from 'react-router-dom';
import { getToken } from '../redux/actions/auth';
import axios from 'axios';

const AddCreation = () => {
  const { reset } = useForm();
  const navigate = useNavigate();
  const [creation, setCreation] = useState({});
  const { currentUser } = useSelector((state) => state.auth);

  useEffect(() => {
    if (currentUser.role !== 'admin') {
      navigate("/creations");
    }
  }, [currentUser.role, navigate]);
 
  const handleChange = (e) => {
    e.preventDefault(); 
    setCreation({ ...creation, [e.target.name]: e.target.value });
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const data = new FormData();
    const img = document.getElementById('art_image');

    data.append('image_url', img.files[0]);
    data.append('artist', creation.artist);
    data.append('title', creation.title);
    // 省略其他字段append逻辑
    axios.post('http://localhost:3001/v1/creations', data, {
      headers: {
        'Content-Type': 'multipart/form-data',
        Authorization: getToken(),
      },
    })
      .then((response) => {
        console.log(response);
        navigate('/');
      })
      .catch((error) => {
        console.log(error);
      });
    reset();
  };

  return (
    <main className="">
      <div className="my-5 d-flex flex-column align-items-center">
        <h2>Add a Creation to Listing</h2>
        <form className="my-5 d-flex flex-row justify-content-center border border-dark" onSubmit={handleSubmit}>
          <div className="my-5 mx-5">
            <div className="d-flex flex-row justify-content-between my-3">
              <label
                className=""
                htmlFor="artist-name"
              >
                Artist Name:
              </label>
              <input
                className=""
                id="artist"
                type="text"
                name="artist"
                onChange={handleChange}
                required
              />
            </div>
            {/* 省略其他输入字段 */}
            <div className="my-3">
              <button className="btn btn-primary btn-lg" type="submit" >
                Add Creation
              </button>
            </div>
          </div>
        </form>
      </div>
    </main>
  );
};

export default AddCreation;
解决思路

1. 排查Redux中currentUser的状态同步问题

  • 检查登录action的逻辑:确认登录成功后,后端返回的用户数据是否被正确存入Redux的auth state,特别是currentUser字段是否包含role属性。
  • 验证useAuth hook的实现:确保loggedIn状态与currentUser的初始化同步,避免出现loggedIn为true但currentUser仍为undefined的情况。

2. 验证后端返回的用户数据格式

  • 在登录请求的响应中打印返回内容,确认role字段是否为字符串'admin'(而非数字1)。Rails enum默认序列化后返回字符串键,但需确认控制器是否正确提取了序列化后的属性:
    • 在后端控制台执行UserSerializer.new(User.find_by(email: 'admin@gmail.com')).serializable_hash,检查输出的role值是否为'admin'。
    • 确认控制器代码中serializable_hash[:data][:attributes]的取值是否正确,避免因哈希取值错误导致role字段丢失。

3. 修复组件内的权限判断逻辑

  • 增加currentUser的存在性校验,避免因currentUser为undefined触发错误重定向:
    useEffect(() => {
      if (!currentUser || currentUser.role !== 'admin') {
        navigate("/creations");
      }
    }, [currentUser, navigate]);
    
  • 若currentUser是异步加载的,结合authChecked状态等待校验完成后再执行判断:
    const { authChecked } = useAuth();
    
    useEffect(() => {
      if (authChecked) {
        if (!currentUser || currentUser.role !== 'admin') {
          navigate("/creations");
        }
      }
    }, [authChecked, currentUser, navigate]);
    

4. 优化路由层面的权限控制

  • 考虑将管理员权限校验整合到路由层,新增AdminProtectedRoutes组件,统一处理角色校验逻辑,避免在组件内重复编写权限判断:
    const AdminProtectedRoutes = ({ isAllowed, authChecked, redirectPath, children }) => {
      const { currentUser } = useSelector(state => state.auth);
      if (!authChecked) return <Loading />;
      if (!isAllowed || (currentUser && currentUser.role !== 'admin')) {
        return <Navigate to={redirectPath} />;
      }
      return children;
    };
    
    之后在路由配置中替换原有的ProtectedRoutes:
    <Route element={<AdminProtectedRoutes isAllowed={loggedIn} authChecked={authChecked} redirectPath="/creations" />}>
      <Route path="/" element={<AddCreation />} />
    </Route>
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 20:42:27