Ionic应用按普通/Premium用户角色控制Firebase数据访问权限
Firebase+Ionic 帖子权限管控最安全实现方案
核心原则先讲死:只在前端做权限过滤等于没做防护,前端代码可以被反编译、篡改,请求可以被抓包重放,真正的安全防线必须落在Firebase服务端,前端只做体验层面的适配。
第一步:配置服务端安全防线(必做,否则所有权限管控都是摆设)
首先不要把用户角色存在实时数据库的普通节点里——只要用户有对应节点的写权限,就能直接改自己的角色提权。官方推荐的角色存储方案是用Firebase Auth的自定义Claims,这个字段存在用户的认证Token里,只有你用服务端的Admin SDK才能修改,用户端完全篡改不了。
你需要在用户注册、会员开通/到期的逻辑里(这段代码必须跑在你自己的服务端或者Firebase云函数里,绝对不能打包到前端代码中),给用户打角色标记:
// 服务端/云函数运行的Admin SDK代码示例 const admin = require("firebase-admin"); // 给普通用户设置角色 await admin.auth().setCustomUserClaims(普通用户的uid, { role: "normal" }); // 给付费Premium用户设置角色 await admin.auth().setCustomUserClaims(Premium用户的uid, { role: "premium" });
接下来配置实时数据库安全规则,直接在数据库层面拦截无权限请求,规则如下:
{ "rules": { "posts": { // 核心读规则:用户已登录,且自身角色在帖子的access权限列表里才允许读 ".read": "auth != null && data.child('access').val().includes(auth.token.role)", // 写权限按需配置,比如仅管理员可以发帖子 ".write": "auth != null && auth.token.role === 'admin'", // 写入格式校验,防止乱存不符合结构的数据 ".validate": "newData.hasChildren(['text', 'access']) && newData.child('access').isArray()" } } }
这套规则生效后,就算用户改了前端代码、手动构造请求读Premium专属帖子,请求会直接被Firebase服务端拒绝,半条数据都拿不到,这才是真正的安全兜底。
第二步:Ionic前端适配(仅做体验优化,不承担安全校验职责)
前端不需要拉全量帖子再过滤(既浪费流量,又会触发无权限请求报错),直接结合当前用户的角色查询对应有权限的内容即可,示例代码(基于Angular版Ionic,Vue/React版逻辑完全一致):
import { Injectable } from '@angular/core'; import { Database, ref, query, orderByChild, equalTo, onValue } from '@angular/fire/database'; import { Auth, authState } from '@angular/fire/auth'; import { Observable, switchMap } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class PostService { constructor(private db: Database, private auth: Auth) {} getAccessiblePosts(): Observable<Array<{id:string, text:string, access:string[]}>> { return authState(this.auth).pipe( switchMap(user => { if (!user) throw new Error('请先登录'); // 从当前用户的认证信息里取角色,仅用于构造查询,不作为权限校验依据 const customClaims = JSON.parse((user as any).reloadUserInfo.customAttributes || '{}'); const currentRole = customClaims.role || 'normal'; // 查询access数组包含当前用户角色的帖子 const postsRef = ref(this.db, 'posts'); const permissionQuery = query( postsRef, orderByChild('access'), equalTo(currentRole) ); return new Observable(subscriber => { const unsubscribe = onValue(permissionQuery, (snapshot) => { const postList = []; snapshot.forEach(childSnap => { postList.push({ id: childSnap.key, ...childSnap.val() }); return false; }); subscriber.next(postList); }, err => subscriber.error(err)); return () => unsubscribe(); }); }) ); } }
页面里直接调用这个服务拿帖子渲染就行,不需要额外做权限判断——就算前端这里拿到的角色被篡改,查询请求到Firebase的时候还是会被安全规则二次校验,不会漏数据。
避坑提醒
- 绝对不要拉全量帖子在前端用if判断过滤:这种方式相当于把所有Premium内容直接下发到用户客户端,哪怕你不在页面渲染,用户抓包就能拿到全部内容,没有任何安全性可言。
- 不要跳过安全规则配置:Firebase实时数据库默认是权限全开的,只要你没写规则,任何人拿到你的数据库地址就能爬走所有数据。
- 不要在客户端代码里写Admin SDK相关逻辑:Admin SDK拥有数据库的全部操作权限,一旦把服务账号密钥打包到前端,整个数据库就完全失控了。
内容的提问来源于stack exchange,提问作者koper92
相关产品推荐
相关产品推荐

