在firebase密钥中替换无效字符的好方法?

时间:2015-08-09 12:16:38

标签: firebase

我的用例是保存用户的信息。当我尝试使用用户的电子邮件地址作为密钥将数据保存到Firebase时,Firebase会抛出以下错误:

  

错误:密钥e@e.ee无效(不能包含.$[]#

所以,显然,我无法通过电子邮件索引用户信息。替换.的最佳做法是什么?

我已成功将.更改为-,但由于某些电子邮件地址中包含-,因此不会删除它。

目前,我正在使用

var cleanEmail = email.replace('.','`');

但是可能会出现与此相关的冲突。

4 个答案:

答案 0 :(得分:19)

在电子邮件地址中,将逗号.替换为,。这种模式是最佳实践。

逗号, 是电子邮件地址中的允许字符,但 允许使用Firebase密钥。对称地,点. 在电子邮件地址中是允许的字符,但在Firebase密钥中是允许的。因此,直接替代将解决您的问题。您可以在不循环的情况下索引电子邮件地址。

您还有另一个问题。在您的代码中:

var cleanEmail = email.replace('.',',');

只会替换第一个点.但电子邮件地址可以包含多个点。要替换所有点,请使用正则表达式

var cleanEmail = email.replace(/\./g, ',');

答案 1 :(得分:9)

我们已经多次处理过这个问题,而表面上似乎使用电子邮件作为关键是一个简单的解决方案,它会导致很多其他问题:必须清理/解析电子邮件以便它实际上可以使用。如果电子邮件发生了变化怎么办?

我们发现更改数据存储方式的格式是一条更好的路径。假设您只需要存储一个用户名。

john@somecompany.com: "John Smith"

将其更改为

randomly_generated_node_name
   email:  "john@somecompany.com"
   first:  "John"
   last:   "Smith"

random_generated_node_name是Firebase可以通过childByAutoId生成的字符串,或者实际上与数据没有直接关系的任何类型的引用。

这提供了很大的灵活性:您现在可以更改姓氏 - 比如说他们结婚了。或者更改电子邮件。你可以添加一个'索引'可用于分类的子0,1,2等。可以查询任何子数据的数据。全部是因为random_generated_node_name是对节点内变量子数据的静态引用。

它还允许您在将来扩展数据而不更改现有数据。添加地址,最喜欢的食物,分类索引等。

编辑:ObjC中的电子邮件Firebase查询:

//references all of the users ordered by email
FQuery *allUsers = [myUsersRef queryOrderedByChild:@"email"];

//ref the user with this email
FQuery *thisSpecificUser = [allUsers queryEqualToValue:@“john@somecompany.com”]; 

//load the user with this email
[thisSpecificUser observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
  //do something with this user
}];

答案 2 :(得分:3)

我可以想出解决这个问题的两种主要方法:

  1. 编码/解码功能
  2. 由于Firebase密钥中允许的字符集有限,因此解决方案是将密钥转换为有效格式(编码)。然后使用反函数( decode )将编码密钥转换回原始密钥。

    通用编码/解码功能可能将原始密钥转换为字节,然后将它们转换为十六进制表示。但是密钥的大小可能是一个问题。

    假设您希望使用电子邮件将用户存储为密钥:

    # path: /users/{email} is User;
    /users/alice@email.com: {
        name: "Alice",
        email: "alice@email.com"
    }
    

    由于路径中的点,上面的示例不起作用。因此我们使用encode函数将密钥转换为有效格式。十六进制的alice@email.com616c69636540656d61696c2e636f6d,然后是:

    # path: /users/{hex(email)} is User;
    /users/616c69636540656d61696c2e636f6d: {
        name: "Alice",
        email: "alice@email.com"
    }
    

    任何客户端都可以访问该资源,只要它们共享相同的hex函数。

    编辑:Base64也可用于编码/解码密钥。可能比十六进制更有效,但有许多不同的实现。如果客户没有共享完全相同的实现,那么它们将无法正常工作。

    也可以使用专门的功能(例如,仅处理电子邮件)。但一定要处理所有边缘情况。

    1. 使用存储的原始密钥编码功能
    2. 单向转换键非常容易。因此,不要使用解码功能,只需将原始密钥存储在数据库中。

      对于这种情况,一个好的编码函数是SHA-256算法。它是许多平台中实现的通用算法。碰撞的可能性很小。

      上一个使用SHA-256的示例如下所示:

      # path: /users/{sha256(email)} is User;
      /users/55bf4952e2308638427d0c28891b31b8cd3a88d1610b81f0a605da25fd9c351a: {
          name: "Alice",
          email: "alice@email.com"
      }
      

      任何具有原始密钥(电子邮件)的客户端都可以找到此条目,因为编码功能是已知的(已知)。而且,即使密钥变大,SHA-256的大小也始终相同,因此保证是有效的Firebase密钥。

答案 3 :(得分:0)

我正在使用以下代码将电子邮件转换为哈希,然后将哈希用作Firebase中的键

public class HashingUtils {
    public HashingUtils() {
    }

    //generate 256 bits hash using SHA-256
    public String generateHashkeySHA_256(String email){
        String result = null;
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(email.getBytes("UTF-8"));
            return byteToHex(hash); // make it printable
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    //generate 160bits hash using SHA-1
    public String generateHashkeySHA_1(String email){
        String result = null;
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-1");
            byte[] hash = digest.digest(email.getBytes("UTF-8"));
            return byteToHex(hash); // make it printable
        }catch(Exception ex) {
            ex.printStackTrace();
        }
        return result;
    }

    public String byteToHex(byte[] bytes) {
        Formatter formatter = new Formatter();
        for (byte b : bytes) {
            formatter.format("%02x", b);
        }
        String hex = formatter.toString();
        return hex;
    }
}

用于将用户添加到Firebase的代码

public void addUser(User user) {
    Log.d(TAG, "addUser: ");
    DatabaseReference userRef= database.getReference("User");

    if(!TextUtils.isEmpty(user.getEmailId())){
       String hashEmailId= hashingUtils.generateHashkeySHA_256(user.getEmailId());
        Log.d(TAG, "addUser: hashEmailId"+hashEmailId);
        userRef.child(hashEmailId).setValue(user);
    }
    else {
        Log.d(TAG,"addUser: empty emailId");
    }
}