React.js项目中基于Firebase Authentication实现多类型用户身份区分问询
嘿,这个问题我之前帮不少开发者捋清楚过——Firebase Auth本身确实只负责身份验证(确认用户是他们说的那个人),但用户角色的区分和权限控制,完全可以通过结合Firebase的其他服务来实现,给你一套落地性很强的方案:
简单来说,用Firebase Auth处理登录/注册的身份验证流程,用Firestore存储每个用户的角色信息(super-admin、vendor-admin、vendor-staff),后续通过读取数据库的角色来做权限判断。
1. 先搞定基础用户认证
不管你用邮箱密码登录、Google第三方登录还是其他方式,先把Firebase Auth的基础流程搭好。比如React里的邮箱密码登录示例:
import { signInWithEmailAndPassword } from "firebase/auth"; import { auth } from "../firebase/config"; const handleLogin = async (email, password) => { try { await signInWithEmailAndPassword(auth, email, password); // 登录成功后跳转到首页或获取角色 } catch (error) { console.error("登录失败:", error.message); } };
2. 存储用户角色信息
用户注册成功后,立刻在Firestore里创建一个users集合,每个文档的ID直接用用户的UID(Firebase Auth返回的user.uid),文档里存role字段和其他必要信息。
两种角色写入方式:
- 普通用户/供应商员工:注册时由前端传入角色(但要注意,供应商管理员最好不要让普通用户自行注册,避免权限滥用)
- 超级管理员:直接在Firebase控制台手动创建用户,然后去Firestore里手动设置
role: "super-admin",绝对不要让前端有创建超级管理员的权限!
注册时写入角色的代码示例:
import { createUserWithEmailAndPassword } from "firebase/auth"; import { doc, setDoc } from "firebase/firestore"; import { auth, db } from "../firebase/config"; const handleRegister = async (email, password, role) => { try { const userCredential = await createUserWithEmailAndPassword(auth, email, password); const user = userCredential.user; // 写入用户信息到Firestore await setDoc(doc(db, "users", user.uid), { email: user.email, role: role, // 这里可以限制只能传入vendor-staff,管理员角色手动设置 createdAt: new Date() }); } catch (error) { console.error("注册失败:", error.message); } };
3. 登录后获取并全局管理角色
用户登录成功后,通过UID从Firestore拉取角色信息,然后存在React的状态管理工具里(比如Context、Redux),这样整个应用都能随时获取用户角色。
用React Context实现的示例:
import { useEffect, useState, createContext, useContext } from "react"; import { onAuthStateChanged } from "firebase/auth"; import { doc, getDoc } from "firebase/firestore"; import { auth, db } from "../firebase/config"; const UserContext = createContext(); export const UserProvider = ({ children }) => { const [currentUser, setCurrentUser] = useState(null); const [userRole, setUserRole] = useState(null); const [loading, setLoading] = useState(true); useEffect(() => { // 监听用户登录状态变化 const unsubscribe = onAuthStateChanged(auth, async (user) => { if (user) { setCurrentUser(user); // 从Firestore获取角色 const userDoc = await getDoc(doc(db, "users", user.uid)); if (userDoc.exists()) { setUserRole(userDoc.data().role); } } else { setCurrentUser(null); setUserRole(null); } setLoading(false); }); // 组件卸载时取消监听 return unsubscribe; }, []); return ( <UserContext.Provider value={{ currentUser, userRole, loading }}> {!loading && children} </UserContext.Provider> ); }; // 自定义Hook,方便组件获取用户信息 export const useUser = () => useContext(UserContext);
记得在App.js里用UserProvider包裹所有组件:
import { UserProvider } from "./UserContext"; function App() { return ( <UserProvider> {/* 你的路由和组件 */} </UserProvider> ); }
4. 实现权限控制
有了全局的角色信息,就可以在路由和组件里做权限判断了。
路由保护
比如只有超级管理员能访问的后台页面:
import { Navigate } from "react-router-dom"; import { useUser } from "./UserContext"; const ProtectedRoute = ({ children, allowedRoles }) => { const { userRole, loading } = useUser(); if (loading) return <div>加载中...</div>; // 没有登录或者角色不在允许列表里,跳转到登录页 if (!userRole || !allowedRoles.includes(userRole)) { return <Navigate to="/login" replace />; } return children; }; // 使用示例 <Route path="/super-admin/dashboard" element={ <ProtectedRoute allowedRoles={["super-admin"]}> <SuperAdminDashboard /> </ProtectedRoute> }/>
组件内权限控制
在组件里根据角色显示不同内容:
import { useUser } from "./UserContext"; const Dashboard = () => { const { userRole } = useUser(); return ( <div className="dashboard"> <h1>欢迎来到控制台</h1> {userRole === "super-admin" && ( <button>管理所有供应商</button> )} {userRole === "vendor-admin" && ( <button>管理我的员工</button> )} {userRole === "vendor-staff" && ( <div> <h3>你的今日任务</h3> {/* 员工任务列表 */} </div> )} </div> ); };
5. 关键! 设置Firestore安全规则
千万别忘了设置Firestore的安全规则,防止用户篡改自己的角色信息!比如:
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 用户只能读取自己的信息 match /users/{userId} { allow read: if request.auth != null && request.auth.uid == userId; // 只有超级管理员能修改用户角色 allow write: if request.auth != null && get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "super-admin"; } // 供应商相关集合,只有超级管理员和供应商管理员能访问 match /vendors/{vendorId} { allow read, write: if request.auth != null && (get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "super-admin" || get(/databases/$(database)/documents/users/$(request.auth.uid)).data.role == "vendor-admin"); } } }
这样就完成了从认证到角色识别,再到权限控制的完整流程,完全适配你三种用户类型的需求。
内容的提问来源于stack exchange,提问作者Mujtaba Zaidi

