Firebase 身份验证与 AWS Cognito [关闭]

Posted

技术标签:

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

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

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

【问题讨论】:

【参考方案1】:

TL;DR; Firebase > 认知

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

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

我们通过 API Gateway 的自定义授权器让 Firebase 工作。在所有客户端(iosandroid 和 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。不过有几件事:

    为每个 JWT 启用 1 小时的缓存,从而大大简化了调用。 不断调用 lambda,因此不应出现冷启动,并且 前一百万个 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

【讨论】:

看起来至少现在存在。 docs.aws.amazon.com/solutions/latest/…【参考方案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 之间进行数据同步

【讨论】:

以上是关于Firebase 身份验证与 AWS Cognito [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

应用离线时如何绕过 Firebase 身份验证?

将 Firebase 身份验证与 Firebase 数据库连接

将 Firebase 身份验证与自定义提供程序一起使用

如何将 Google Play 游戏登录与 Firebase 身份验证结合使用

Firebase 权限被拒绝(读取和写入)与身份验证

Firebase 身份验证 UI - 登录与注册