Authentication 如何使用Firebase登录多个社会服务?

Authentication 如何使用Firebase登录多个社会服务?,authentication,facebook-authentication,firebase,firebase-security,Authentication,Facebook Authentication,Firebase,Firebase Security,我希望用户能够使用多个不同的身份验证提供商(如Facebook、Twitter或Github)对我的Firebase应用程序进行身份验证。一旦通过身份验证,我希望用户能够访问相同的帐户,无论他们使用哪种身份验证方法 换句话说,我想在我的应用程序中将多个身份验证方法合并到一个帐户中。如何在Firebase应用程序中执行此操作? 更新(20160521):Firebase刚刚发布了其产品的主要更新,现在允许单个用户链接来自各种受支持提供商的帐户。要了解有关此功能的更多信息,请阅读和的文档。下面的答案

我希望用户能够使用多个不同的身份验证提供商(如Facebook、Twitter或Github)对我的Firebase应用程序进行身份验证。一旦通过身份验证,我希望用户能够访问相同的帐户,无论他们使用哪种身份验证方法

换句话说,我想在我的应用程序中将多个身份验证方法合并到一个帐户中。如何在Firebase应用程序中执行此操作?


更新(20160521):Firebase刚刚发布了其产品的主要更新,现在允许单个用户链接来自各种受支持提供商的帐户。要了解有关此功能的更多信息,请阅读和的文档。下面的答案是出于历史原因留下的


核心Firebase服务提供了几种身份验证方法:

Firebase的核心是使用安全的JWT令牌进行身份验证。产生JWT令牌的任何结果(例如在您自己的服务器上使用JWT库)都将用于向Firebase验证您的用户,因此您可以完全控制验证过程

Firebase提供了一个名为Firebase Simple Login的服务,这是生成这些令牌的一种方式(这提供了我们的Facebook、Twitter等身份验证)。它适用于常见的身份验证场景,这样您就可以在没有服务器的情况下快速启动和运行,但它不是唯一的身份验证方法,也不是一个全面的解决方案

以下是一种允许使用Firebase Simple login与多个提供商登录的方法:

  • 为每个用户存储一个规范用户标识符,并为 每个提供程序特定的标识符都指向该规范id
  • 更新您的安全规则,使其与服务器上的任何凭据相匹配 给定的用户帐户,而不仅仅是一个
  • 实际上,安全规则可能如下所示,假设您希望同时启用Twitter和Facebook身份验证(或允许用户使用其中一个创建帐户,然后再添加另一个):

    在本例中,您存储一个全局用户id(可以是您选择的任何内容),并维护Facebook、Twitter等身份验证机制与主用户记录之间的映射。在每个用户登录后,您将从用户映射中获取主用户记录,并使用该id作为用户数据和操作的主存储。上述内容还限制和验证用户映射中的数据,以便只有在/users/$userid/(Facebook id | Twitter id | etc id)下已经拥有相同Facebook、Twitter等用户id的适当用户才能将其写入

    这种方法可以让您快速启动并运行。但是,如果您有一个复杂的用例,并且希望完全控制身份验证体验,那么您可以在自己的服务器上运行自己的身份验证代码。有许多有用的开源库可以用来实现这一点,例如和


    您还可以使用第三方身份验证提供程序进行身份验证。例如,您可以使用,它有大量现成的集成,而无需编写任何服务器端代码。

    我知道这篇文章已经存在好几个月了,但当我面对这个问题时,我花了很多时间使代码更加灵活。基于上面的Andrew代码,我稍微调整了代码

    示例数据存储:

    安全规则:

    因此,用户映射仍然是我们在Facebook、Twitter等网站上登录时查找的第一个信息。。。。userMappings的用户将指向users中的主帐户。因此,在通过Facebook或Twitter登录后,我们可以查找主用户帐户。在users中,我们保留了可以访问其数据的userMapping列表


    当创建新用户时,我们必须首先在用户中创建一个帐户。用户中用户的id可以是我们想要的任何内容。这是灵活的,因为我们可以提供更多的登录方法,如Google、Github,而无需添加更多的安全规则。

    我刚刚创建了一个angularfire装饰程序来为我们处理这个问题:

    我花了相当长的时间思考一个好的解决方案,而我如何能够从任何提供商注册只是让人困惑。在我的前端,我总是要求注册电子邮件,因此,例如,使用facebook和google+登录的用户在通知其电子邮件时,将以同一用户的身份登录

    这样,Kuma提出的示例数据就不需要重复userMappings

    样本数据存储:

    userMappings
    |---facebook:777
    |   |---user:"123"
    |---twitter:888
        |---user:"123"
    users
    |---123
        |---user data
    

    关于这个策略,我有几个问题要问你:我看不出
    .child('twitter/id').val()
    .child('twitter-id').val()之间的区别。两个参考文献都不同吗?我没听懂。非常感谢您提供的映射示例。有没有可能在iOS上继续编写一些代码来说明如何做到这一点?我已经在一个生产应用程序上使用了一个非常类似的系统有一段时间了。我的数据结构只是有点不同。在用户映射下,我只有一个UID列表。我还没有找到任何理由将它们分解为提供者桶。。。尽管每个节点最终都会使用提供者名称进行标记。这种稍微浅一点的数据结构允许您对所有用户映射运行查询,因此您可以快速关联使用不同方法但使用相同电子邮件地址登录的用户。这里有一些文档:这可能是一个很好的解决方案,但从来没有网络向用户提供电子邮件,也从来没有用户允许阅读他们的电子邮件。。。如果不是通过电子邮件“关联”两个用户和用户映射,那么“粘合剂”是什么呢?这似乎是一个很好的解决方案,但它让我在一个方面感到疑惑/受阻:具有正确auth.uid的请求将能够自然地访问它需要的“用户映射”(检查!),并且还能够通过在其上进行查找来访问它需要的“用户”“userMappings”子项(有点笨重,但请检查!)。但是当我们有其他数据/字段时,比如说“userActivity”或“userPosts”,如何使这些字段仅由创建它们的用户编写呢
    
    userMappings
    |---facebook:777
    |   |---user:"123"
    |---twitter:888
        |---user:"123"
    users
    |---123
        |---userMappings
            |---facebook: "facebook:777"
            |---twitter: "twitter:888"
    
    "userMappings": {
      "$login_id": {
        ".read": "$login_id === auth.uid",
        ".write": "auth!== null && (data.val() === null || $login_id === auth.uid)"
      }
    },
    
    "users": {
      "$user_id": {
        ".read": "data.child('userMappings/'+auth.provider).val()===auth.uid",
        ".write": "auth!= null && (data.val() === null || data.child('userMappings/'+auth.provider).val()===auth.uid)"
      }
    }
    
    userMappings
    |---facebook:777
    |   |---user:"123"
    |---twitter:888
        |---user:"123"
    users
    |---123
        |---user data