使用Firebase Realtime Database验证内购时点号路径存储方案咨询
Firebase Realtime Database存储含点号purchaseToken的正确方案
Firebase Realtime Database 对路径键有明确的字符限制,禁止包含.、#、$、[、]、/ 几类字符,你提到的直接剔除点号的方案存在哈希碰撞风险,不推荐使用——极端场景下两个不同的purchaseToken剔除点号后可能生成完全相同的字符串,直接导致购买记录串号、校验逻辑失效。
以下是生产环境验证过的合规实现方案:
- 优先选择:URL安全Base64编码后作为路径键
这是Firebase官方社区推荐的标准处理方式,编码过程无碰撞、可逆,生成的字符串完全不含RTDB禁止的特殊字符,不需要额外维护字符映射规则。实现逻辑非常简单:Cloud Functions拿到客户端上传的purchaseToken后,先做URL安全变体的Base64编码,用编码结果作为RTDB路径键存储购买记录;后续校验时,对传入的待校验token做完全相同的编码处理,再查询对应路径是否存在记录即可。
Cloud Functions(Node.js环境)示例代码:// 将原始purchaseToken转为RTDB兼容的安全键 const getSafePurchaseKey = (purchaseToken) => { return Buffer.from(purchaseToken).toString('base64url'); }; // 查询购买记录示例 const purchaseRef = admin.database().ref(`purchases/${getSafePurchaseKey(purchaseToken)}`); - 轻量方案:一对一字符替换
如果不想引入编码逻辑,可以将点号替换为绝对不会出现在原始purchaseToken字符集中的占位符。Google Play颁发的purchaseToken字符集仅包含大小写字母、数字、-、_、~,不会出现自定义占位符,因此可以将.全局替换为比如_DOT_这类固定字符串,保证每个原始token和存储键是一一对应的关系,绝对不能直接删除点号。
示例处理逻辑:const getSafePurchaseKey = (purchaseToken) => { return purchaseToken.replace(/\./g, '_DOT_'); }; - 结构调整方案:不将purchaseToken作为路径键
RTDB仅对路径键有字符限制,对节点内存储的字段值没有任何字符限制。你可以调整存储结构,用本身不含特殊字符的订单ID(orderId)作为路径键,把purchaseToken作为对应节点下的普通字段存储;校验时通过orderByChild('purchaseToken').equalTo(待校验token)的方式查询记录是否存在。注意使用该方案必须在RTDB规则中给purchaseToken字段配置索引,否则数据量上涨后查询性能会严重下降。
实现校验逻辑时需要遵循Play Billing的安全规范:所有购买状态校验、token处理逻辑必须在Cloud Functions服务端完成,RTDB的购买记录节点要配置安全规则,仅允许服务账号拥有读写权限,禁止客户端直接读写该节点,避免数据被篡改。
内容的提问来源于stack exchange,提问作者Jay N
相关产品推荐
相关产品推荐

