【问题标题】:Firebase authentication vs AWS Cognito [closed]Firebase 身份验证与 AWS Cognito [关闭]
【发布时间】:2017-03-31 16:23:13
【问题描述】:

我们正在使用 API Gateway 和 Lambda 在 AWS 上构建移动和 Web 应用程序,目前正在评估是否应该使用 AWS CognitoFirebase Auth

AWS Cognito 很好地集成到 API Gateway 和 Lamdba,例如只有经过身份验证的用户才能执行某些 API 调用。如果我们改用 Firebase 身份验证,是否可以达到相同的行为? 有什么好的或坏的经验吗?

【问题讨论】:

    标签: amazon-web-services firebase google-analytics firebase-authentication amazon-cognito


    【解决方案1】:

    TL;DR; Firebase > 认知

    我们首先从 Cognito 开始,但最终我们意识到,当它使用联合身份(例如,Google 登录、Facebook 登录等)时,它有一种难闻的气味。对于 Cognito 用户池(即允许用户使用用户名和密码注册/登录),您可以使用内置的 API Gateway Cognito 用户池授权器,它运行良好。您不需要编写自己的自定义授权者或任何东西。

    但是,如果您想支持联合身份,则需要将 API 网关上的身份验证更改为 IAM Auth,然后让每个客户端 sigv4 对请求进行签名,结果证明这对我们来说是一个棘手的问题,而且成本很高开发时间。选项 2 是让 API Gateway 为每个客户端的 API 调用生成代码......在我看来,这证明了与 Cognito 的繁琐集成。

    我们通过 API Gateway 的自定义授权器让 Firebase 工作。在所有客户端(iOS、Android 和 Web)上都轻而易举。 API Gateway 端点链接到 Lambda 函数,这些函数能够代表调用端点的用户与 DynamoDB、S3 和其他 Web 服务进行通信。 lambda 函数知道调用用户是谁,因为自定义授权方在 JWT 中返回了电子邮件地址。

    这是一个非常基本的 Firebase 自定义授权器,它将 JWT 中的用户电子邮件作为 principalId 返回:

    'use strict';
    console.log('Loading function');
    
    var admin = require('firebase-admin');
    var serviceAccount = require('./my-secret-json.json');
    
    admin.initializeApp({
        credential: admin.credential.cert(serviceAccount),
        databaseURL: 'https://my-app.firebaseio.com'
    });
    
    exports.handler = (event, context, callback) => {
        var token = event.authorizationToken;
    
        if (token == null) {
            callback('Invalid token');
        }
        else {
            admin.auth().verifyIdToken(token)
                .then(function (decodedToken) {
                    var email = decodedToken.email;
                    var policy = generatePolicy(email);
                    callback(null, policy);
                }).catch(function (error) {
                    console.log(error);
                    callback('Unauthorized'); 
                });
        }
    };
    
    var generatePolicy = function (email) {
        return {
            principalId: email,
            policyDocument: {
                Version: '2012-10-17',
                Statement: [
                    {
                        Action: 'execute-api:Invoke',
                        Effect: email ? 'allow' : 'deny',
                        Resource: '*'
                    }
                ]
            }
        };
    }
    

    然后,您可以在 API Gateway 映射模板中使用 $context.authorizer.principalId 来检索电子邮件并将其传递给 lambda X。


    我最初认为延迟会是一个问题,但事实似乎并非如此。我遇到的任何和所有延迟都是由于冷启动而被调用的 lambda 的延迟。我注意到授权 lambda 的寿命比其他 lambda 长得多。


    每个后端请求都会调用这个 lambda。不过有几件事:

    1. 为每个 JWT 启用 1 小时的缓存,从而大大简化了调用。
    2. 不断调用 lambda,因此不应出现冷启动,并且
    3. 前一百万个 lambda 请求/月是免费的,之后每百万个请求/月是 0.20 美元。因此,除非您的 API 每月调用 BILLION 次,否则您不会产生高昂的成本。

    【讨论】:

    • 感谢分享。当我意识到用户池没有在那里实现时,我刚刚遇到了 Unity3d + Cognito 的障碍。我想尝试 Firebase,但不完全切换到 Firebase 或 GCP 作为后端,保留 AWS/API 网关。您是否还获得了联合身份,例如Facebook 和谷歌正在使用 Firebase+API 网关?您在此过程中遇到了什么障碍?
    • 我确实获得了使用 Firebase+API 网关的联合身份。老实说,我不需要在后端做任何特定/自定义的事情。对于客户端,只需确保在连接联合身份后从 Firebase 获取 JWT。如果你有兴趣了解我是如何使用 Swift 在 iOS 客户端中做到这一点的,请告诉我,我会发布一个要点。
    • @AzizJaved 从 lambda 调用 firebase auth 的延迟如何,您认为使用 Cognito 会快得多,因为它是 AWS?
    • 我最初认为延迟会是一个问题,但事实似乎并非如此。我遇到的任何和所有延迟都是由于冷启动而被调用的 lambda 的延迟。我注意到授权 lambda 的寿命比其他 lambda 长得多。
    • 没有。所做的只是检查 JWT 的过期时间和其他一些本地事务。您必须拨打电话询问 Google 令牌是否实际上是由他们生成的。
    【解决方案2】:

    我们也在做同样的事情。

    我们从 Cognito 开始,但迁移到 Firebase,因为我们对 AWS Android SDK 实现与 Google 和 Facebook 的身份验证流程的方式不满意:代码相当陈旧,它使用了已弃用的方法,并且通常需要重写。另一方面,Firebase 身份验证显然可以无缝运行。

    当您不使用 Cognito 时,您需要在 AWS API Gateway 中实现您的自定义身份验证器,这非常简单,在 https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/ 中有描述。令牌验证的 Firebase 说明在 https://firebase.google.com/docs/auth/admin/verify-id-tokens

    以下是我的验证器代码的摘录:

    'use strict';
    
    // Firebase initialization
    // console.log('Loading function');
    const admin = require("firebase-admin");
    admin.initializeApp({
      credential: admin.credential.cert("xxx.json"),
      databaseURL: "https://xxx.firebaseio.com"
    });
    // Standard AWS AuthPolicy - don't touch !!
    ...
    // END Standard AWS AuthPolicy - don't touch !!
    
    exports.handler = (event, context, callback) => {
        // console.log('Client token:', event.authorizationToken);
        // console.log('Method ARN:', event.methodArn);
    
        // validate the incoming token
        // and produce the principal user identifier associated with the token
    
        // this is accomplished by Firebase Admin
        admin.auth().verifyIdToken(event.authorizationToken)
            .then(function(decodedToken) {
                let principalId = decodedToken.uid;
                // console.log(JSON.stringify(decodedToken));
    
                // if the token is valid, a policy must be generated which will allow or deny access to the client
    
                // if access is denied, the client will recieve a 403 Access Denied response
                // if access is allowed, API Gateway will proceed with the backend integration configured on the method that was called
    
                // build apiOptions for the AuthPolicy
                const apiOptions = {};
                const tmp = event.methodArn.split(':');
                const apiGatewayArnTmp = tmp[5].split('/');
                const awsAccountId = tmp[4];
                apiOptions.region = tmp[3];
                apiOptions.restApiId = apiGatewayArnTmp[0];
                apiOptions.stage = apiGatewayArnTmp[1];
                
                const method = apiGatewayArnTmp[2];
                let resource = '/'; // root resource
                if (apiGatewayArnTmp[3]) {
                    resource += apiGatewayArnTmp[3];
                }
                
    
                // this function must generate a policy that is associated with the recognized principal user identifier.
                // depending on your use case, you might store policies in a DB, or generate them on the fly
    
                // keep in mind, the policy is cached for 5 minutes by default (TTL is configurable in the authorizer)
                // and will apply to subsequent calls to any method/resource in the RestApi
                // made with the same token
    
                // the policy below grants access to all resources in the RestApi
                const policy = new AuthPolicy(principalId, awsAccountId, apiOptions);
                policy.allowAllMethods();
                // policy.denyAllMethods();
                // policy.allowMethod(AuthPolicy.HttpVerb.GET, "/users/username");
    
                // finally, build the policy and exit the function
                callback(null, policy.build());
            })
            .catch(function(error) {
                // Firebase throws an error when the token is not valid
                // you can send a 401 Unauthorized response to the client by failing like so:
                console.error(error);
                callback("Unauthorized");
            });
    };
    

    我们尚未投入生产,但对身份验证器的测试表明,它在 Google、Facebook 和密码身份验证中表现正确,而且速度也非常快(60 - 200 毫秒)。 我能看到的唯一缺点是您需要为验证器 lambda 功能付费,而 Cognito 集成验证器是免费的。


    将近 1 年后更新

    我放弃了 API Gateway 自定义身份验证器,主要是因为我无法使用 cloudformation 脚本自动部署它。我现在的解决方案是在一段时间内直接在 API 缓存令牌中进行身份验证,就像 Authenticator 一样,以避免过多的验证。

    【讨论】:

    • 您能否分享更多您对 Cognito 的 Facebook/Google 身份验证不满意的原因?
    • 将近 1 年后更新: - 我离开了 API Gateway 自定义身份验证器,主要是因为我无法使用 cloudformation 脚本自动部署它。我现在的解决方案是在一段时间内直接在 API 缓存令牌中进行身份验证,就像 Authenticator 所做的那样,以避免过多的验证。
    • 第三方 jwt 库 firebase.google.com/docs/auth/admin/… 是否会保存往返以验证 Firebase 帐户?
    • AFAIK 提供的库也是如此,只是让您无需从头开始编写所有代码。除非您必须刷新密钥,否则不需要往返。
    • 你知道你不喜欢 Cognito 的事情是否仍然是真的吗?
    【解决方案3】:

    对我来说,如果您决定转而使用其他身份验证服务提供商,那么交易破坏者就是能够导出用户的所有详细信息。

    虽然这在 Firebase 中是可能的,但在 AWS Cognitio 中不可用! 你可以进入一年中的任何时间,但你永远不能离开:)。 https://forums.aws.amazon.com/thread.jspa?threadID=296932

    【讨论】:

    【解决方案4】:

    如果您使用 Unity,目前 Unity SDK 不支持 Cognito 用户池。 (即AWS托管的用户列表)我目前正在犹豫。请参阅我的帖子here,他们确认这是真的,目前(26/06/2017)该功能仍然不可用,这可能表明他们对 Unity 用户缺乏关注。

    但是,如果我使用 Firebase 进行登录,我需要对这些凭证进行更多集成才能使用 AWS 服务。 (我想使用 S3 和 DynamoDB,但只有登录用户才能使用它。)这也让我意识到我应该将所有东西都转移到 Firebase 以尽快节省我的时间和挫败感。 (实时数据库比 S3/DynamoDB 贵,但 Unity 有自己的 AWS MobileAnalytics 替代品)

    AWS S3 最近有了更好的 UI,我认为这接近 Google 的水平。但除此之外,我认为 Firebase 的 UI 使用起来更有趣。

    此外,Firebase 身份验证是免费的,而 Cognito 每月有多达 5 万名活跃用户免费。 (接下来的 50k 将花费 0.0055,这意味着如果您有 100k MAU,它将是 50000 * 0.0055 = 275 USD https://aws.amazon.com/cognito/pricing/

    还有一点,在我看来,AWS .NET documentation 是阅读/搜索的噩梦。

    【讨论】:

    • 我可以轻松地将 S3 和 DynamoDB 与 Firebase 身份验证一起使用。您的客户端调用连接到 lambda X 的 API Gateway 端点,并从 Firebase 传递 JWT。您在自定义授权方中验证 JWT 令牌,然后将用户电子邮件传递给 lambda X。只要 X 具有对 DynamoDB 和 S3 的 IAM 访问权限,它就可以获取用户的资源,并将其作为来自 API Gateway 的响应返回。
    【解决方案5】:

    aws cognito 提供了比 firebase 更多的用户身份验证方式。特别是,如果您正在构建一个游戏,它提供了通过 google 和 ios 游戏中心登录的便利。它提供游戏中心提供的同步排行榜和成就。 Cognito 中有自动状态同步功能。但毫无疑问,这非常令人困惑。实施需要太多时间。另一方面,firebase 身份验证的实施速度非常快。

    【讨论】:

      【解决方案6】:

      AWS 文档非常混乱。 Firebase 中更好地记录了不同身份验证步骤的回调系统。结果是更简洁的代码和对身份验证流程的更好控制。此外,Firebase 用户界面更加人性化。如果您打算使用内容提供程序和同步适配器,我建议您使用 Firebase,因为您将有简单的方法在本地和远程 (Firebase) db 之间进行数据同步

      【讨论】:

        猜你喜欢
        • 2018-01-29
        • 2014-09-30
        • 2016-06-25
        • 1970-01-01
        • 2017-01-02
        • 2018-05-22
        • 2016-12-22
        • 2022-01-26
        • 2020-01-30
        相关资源
        最近更新 更多