我可以想到两种主要的方法来解决这个问题:
- 编码/解码功能
由于 Firebase 密钥中允许的字符集有限,解决方案是将密钥转换为有效格式(编码)。然后有一个反函数(decode)将编码的密钥转换回原始密钥。
一般的编码/解码函数可能会将原始密钥转换为字节,然后将它们转换为十六进制表示。但是密钥的大小可能是个问题。
假设您想使用电子邮件作为键来存储用户:
# path: /users/{email} is User;
/users/alice@email.com: {
name: "Alice",
email: "alice@email.com"
}
由于路径中的点,上面的示例不起作用。所以我们使用encode函数将key转换成有效的格式。十六进制的alice@email.com是616c69636540656d61696c2e636f6d,那么:
# path: /users/{hex(email)} is User;
/users/616c69636540656d61696c2e636f6d: {
name: "Alice",
email: "alice@email.com"
}
只要共享相同的hex 函数,任何客户端都可以访问该资源。
编辑:Base64 也可用于对密钥进行编码/解码。可能比十六进制更有效,但有许多不同的实现。如果客户端不共享完全相同的实现,那么它们将无法正常工作。
也可以使用专门的功能(例如仅处理电子邮件)。但一定要处理所有的边缘情况。
- 存储原始密钥的编码函数
对密钥进行单向转换要容易得多。因此,不要使用解码函数,只需将原始密钥存储在数据库中即可。
在这种情况下,一个很好的编码函数是 SHA-256 算法。这是一种在许多平台上都有实现的通用算法。而且发生碰撞的可能性很小。
前面使用 SHA-256 的示例变成这样:
# path: /users/{sha256(email)} is User;
/users/55bf4952e2308638427d0c28891b31b8cd3a88d1610b81f0a605da25fd9c351a: {
name: "Alice",
email: "alice@email.com"
}
任何具有原始密钥(电子邮件)的客户端都可以找到此条目,因为编码功能是已知的(它是已知的)。而且,即使密钥变大,SHA-256 的大小也始终相同,因此可以保证是有效的 Firebase 密钥。