React Redux Firebase应用:限制Admin端数据库/存储写入权限及路由拦截
嘿,我刚好做过类似的React Redux Firebase项目,咱们一步步来解决这个权限问题,确保只有你指定的管理员才能碰后台和操作资源:
1. 先锁死Firebase的底层安全规则(数据库+Storage)
这是最关键的一步——不管前端怎么控制,底层安全规则是防止越权操作的最后防线,必须先搞定。
首先,你需要在Firebase数据库(Firestore/实时数据库)里专门存一个管理员列表:
- 如果用Firestore,新建一个
admins集合,每个文档的ID就是管理员用户的UID,文档内容可以随便放个true就行(比如文档abc123uidOfAdmin的字段isAdmin: true) - 如果用实时数据库,建一个
admins节点,把管理员UID作为键,值设为true,比如:
{ "admins": { "abc123uidOfAdmin": true, "def456anotherAdminUid": true } }
然后配置安全规则:
Firestore规则示例
rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { // 普通用户可以读取数据(如果不需要的话可以删掉这行) match /{document=**} { allow read: if request.auth != null; // 只有admins集合里存在的用户才能写入 allow write: if exists(/databases/$(database)/documents/admins/$(request.auth.uid)); } } }
实时数据库规则示例
{ "rules": { ".read": "auth != null", // 可选,根据你的需求调整 ".write": "root.child('admins').child(auth.uid).exists()" } }
Storage规则示例
rules_version = '2'; service firebase.storage { match /b/{bucket}/o { match /{allPaths=**} { allow read: if request.auth != null; allow write: if exists(/databases/$(database)/documents/admins/$(request.auth.uid)); } } }
这样一来,就算普通用户登录了,也没法修改数据库和Storage里的内容。
2. 给React路由加权限拦截,挡住非管理员访问/admin路径
接下来处理前端的路由跳转,用React Router配合React Redux Firebase的状态来做权限判断。
首先创建一个专门的AdminRoute组件,用来拦截/admin下的所有路径:
import { Navigate, Outlet } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { useFirestoreConnect } from 'react-redux-firebase'; const AdminRoute = () => { // 把Firestore的admins集合同步到Redux状态里 useFirestoreConnect([{ collection: 'admins' }]); // 从Redux获取当前用户的认证状态和管理员列表 const auth = useSelector(state => state.firebase.auth); const admins = useSelector(state => state.firestore.data.admins); // 判断当前用户是否是管理员 const isAdmin = auth.uid && admins && admins[auth.uid]; // 未登录的话,跳转到登录页 if (!auth.uid) { return <Navigate to="/login" replace />; } // 已登录但不是管理员,跳转到首页或者无权限提示页 if (!isAdmin) { return <Navigate to="/" replace />; } // 是管理员的话,正常渲染后台页面 return <Outlet />; };
然后在你的路由配置里用这个组件包裹所有/admin的子路由:
import { Routes, Route } from 'react-router-dom'; import Home from './pages/Home'; import Login from './pages/Login'; import AdminDashboard from './pages/admin/Dashboard'; import AdminPosts from './pages/admin/Posts'; import AdminRoute from './components/AdminRoute'; function App() { return ( <Routes> {/* 公共可访问的路由 */} <Route path="/" element={<Home />} /> <Route path="/login" element={<Login />} /> {/* 管理员专属路由,只有通过AdminRoute验证的用户才能访问 */} <Route path="/admin" element={<AdminRoute />}> <Route index element={<AdminDashboard />} /> <Route path="posts" element={<AdminPosts />} /> {/* 其他/admin子路由都放在这里面 */} </Route> </Routes> ); }
如果用的是实时数据库,把useFirestoreConnect换成useFirebaseConnect就行,逻辑类似。
3. 可选优化:隐藏非管理员的后台入口
为了提升体验,你可以在导航栏或者登录页面里,根据用户角色来控制是否显示/admin的入口:
import { Link } from 'react-router-dom'; import { useSelector } from 'react-redux'; import { useFirestoreConnect } from 'react-redux-firebase'; const Navbar = () => { useFirestoreConnect([{ collection: 'admins' }]); const auth = useSelector(state => state.firebase.auth); const admins = useSelector(state => state.firestore.data.admins); const isAdmin = auth.uid && admins && admins[auth.uid]; return ( <nav className="navbar"> <Link to="/">首页</Link> {auth.uid ? ( <> {/* 只有管理员能看到后台入口 */} {isAdmin && <Link to="/admin">后台管理</Link>} <button onClick={() => firebase.auth().signOut()}>退出登录</button> </> ) : ( <Link to="/login">登录</Link> )} </nav> ); };
不过要注意,即使隐藏了入口,还是要靠前面的路由拦截和安全规则——因为用户可能直接在地址栏输入/admin路径。
最后再提醒一下
一定要确保安全规则是最先配置的,不要依赖前端的权限控制来保护数据,前端的控制只是提升用户体验,真正的安全还是要靠Firebase的底层规则。
内容的提问来源于stack exchange,提问作者ZachO
相关产品推荐
相关产品推荐

