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,但登录/注册组件可正常连接后端。
后端相关代码
- 种子数据
user_1 = User.create(username: 'Admin User', role: 1, email: 'admin@gmail.com', password: "admin123")
- User模型角色枚举
enum role: %i[user admin] after_initialize :set_default_role, if: :new_record? def set_default_role self.role ||= :user end
- User序列化器
class UserSerializer include FastJsonapi::ObjectSerializer attributes :id, :username, :role, :email end
- 控制器返回数据处理
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的
authstate,特别是currentUser字段是否包含role属性。 - 验证
useAuthhook的实现:确保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
相关产品推荐
相关产品推荐

