Firebase 身份验证与 AWS Cognito
Firebase authentication vs AWS Cognito
我们正在使用 API Gateway 和 Lambda 在 AWS 上构建移动和 Web 应用程序,目前正在评估我们是否应该使用 AWS Cognito 或 Firebase 验证.
AWS Cognito 很好地集成到 API Gateway 和 Lamdba,例如只有经过身份验证的用户才能执行某些 API 调用。如果我们改用 Firebase 身份验证,是否可以实现相同的行为?
有什么好的或坏的经验吗?
我们也在做同样的事情。
我们从 Cognito 开始,但后来转到 Firebase,因为我们对 AWS Android SDK 使用 Google 和 Facebook 实现身份验证流程的方式不满意:代码很旧,它使用已弃用的方法,通常需要重写。另一方面,Firebase 身份验证显然是无缝工作的。
当您不使用 Cognito 时,您需要在 AWS API 网关中实施您的自定义身份验证器,这非常简单,在 https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/. Firebase instructions for token validation are in 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 网关自定义身份验证器,主要是因为我无法使用 cloudformation 脚本自动部署它。我现在的解决方案是在一段时间内直接在 API 缓存令牌中进行身份验证,就像 Authenticator 所做的那样,以避免过度验证。
Aws 文档非常混乱。不同身份验证步骤的回调系统在 Firebase 中有更好的记录。结果是更清晰的代码和对身份验证流程的更好控制。此外,Firebase 用户界面更加人性化。如果您打算使用内容提供程序和同步适配器,我建议您使用 Firebase,因为您将拥有在本地和远程 (Firebase) db
之间进行数据同步的简单方法
aws cognito 提供了比 firebase 更多的用户身份验证方法。特别是,如果您正在构建游戏,它可以方便地通过 google 和 ios 游戏中心登录。它提供同步排行榜和游戏中心提供的成就。 Cognito 中有自动状态同步功能。但可以肯定的是,这非常令人困惑。实施需要太多时间。另一方面,firebase 身份验证的实施速度非常快。
TL;DR; Firebase > 认知
我们首先从 Cognito 开始,但我们最终意识到它在使用联合身份(例如,Google 登录、Facebook 登录等)时有一种难闻的气味。对于 Cognito 用户池(即允许用户使用用户名和密码签署 up/in),您可以使用内置的 API Gateway Cognito 用户池授权器,它工作得很好。您不需要编写自己的自定义授权器或任何东西。
但是,如果您想支持联合身份,则需要将 API 网关上的身份验证更改为 IAM Auth,然后让每个客户端 sigv4 对请求进行签名,结果证明这是一个棘手的问题在我们这边,花费了大量的开发时间。选项 2 是让 API Gateway 为每个客户端的 API 调用生成代码...在我看来,这证明了与 Cognito 的繁琐集成。
我们通过 API 网关的自定义授权器让 Firebase 正常工作。对所有客户端(iOS、Android 和 Web)来说都是轻而易举的事。 API 网关端点链接到 Lambda 函数,这些函数能够代表调用端点的用户与 DynamoDB、S3 和其他 Web 服务进行通信。 lambda 函数知道调用用户是谁,因为自定义授权方在 JWT 中返回了电子邮件地址。
这是一个非常基本的 Firebase 自定义授权方,returns 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 网关映射模板中使用 $context.authorizer.principalId
来检索电子邮件并将其传递给 lambda X。
我最初认为延迟会是一个问题,但事实似乎并非如此。我遇到的所有延迟都是由于冷启动导致调用的 lambda 延迟造成的。我注意到授权 lambda 的寿命比其他 lambda 长得多。
每个后端请求都会调用此 lambda。不过有几件事:
- 为每个 JWT 启用 1 小时的缓存,从而大大简化了调用。
- lambda 不断被调用,所以不应该冷启动,而且
- 前一百万 lambda requests/month 免费,之后每百万 requests/month 0.20 美元。因此,除非您的 API 每月被呼叫十亿次,否则您不会产生高得离谱的费用。
以防万一您使用的是 Unity,目前 Unity SDK 不支持 Cognito 用户池。 (也就是AWS托管的用户列表)我目前正因此而犹豫不决。看到我的 post 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 美元 https://aws.amazon.com/cognito/pricing/)
还有一点,在我看来,AWS .NET documentation 对 read/search 来说是一场噩梦。
对我来说,如果您决定转移到其他身份验证服务提供商,交易破坏者能够导出用户的所有详细信息。
虽然这在 Firebase 中可行,但在 AWS Cognitio 中不可用!
您可以在一年中的任何时间进入,但您永远不能离开 :)。
https://forums.aws.amazon.com/thread.jspa?threadID=296932
我们正在使用 API Gateway 和 Lambda 在 AWS 上构建移动和 Web 应用程序,目前正在评估我们是否应该使用 AWS Cognito 或 Firebase 验证.
AWS Cognito 很好地集成到 API Gateway 和 Lamdba,例如只有经过身份验证的用户才能执行某些 API 调用。如果我们改用 Firebase 身份验证,是否可以实现相同的行为? 有什么好的或坏的经验吗?
我们也在做同样的事情。
我们从 Cognito 开始,但后来转到 Firebase,因为我们对 AWS Android SDK 使用 Google 和 Facebook 实现身份验证流程的方式不满意:代码很旧,它使用已弃用的方法,通常需要重写。另一方面,Firebase 身份验证显然是无缝工作的。
当您不使用 Cognito 时,您需要在 AWS API 网关中实施您的自定义身份验证器,这非常简单,在 https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/. Firebase instructions for token validation are in 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 网关自定义身份验证器,主要是因为我无法使用 cloudformation 脚本自动部署它。我现在的解决方案是在一段时间内直接在 API 缓存令牌中进行身份验证,就像 Authenticator 所做的那样,以避免过度验证。
Aws 文档非常混乱。不同身份验证步骤的回调系统在 Firebase 中有更好的记录。结果是更清晰的代码和对身份验证流程的更好控制。此外,Firebase 用户界面更加人性化。如果您打算使用内容提供程序和同步适配器,我建议您使用 Firebase,因为您将拥有在本地和远程 (Firebase) db
之间进行数据同步的简单方法aws cognito 提供了比 firebase 更多的用户身份验证方法。特别是,如果您正在构建游戏,它可以方便地通过 google 和 ios 游戏中心登录。它提供同步排行榜和游戏中心提供的成就。 Cognito 中有自动状态同步功能。但可以肯定的是,这非常令人困惑。实施需要太多时间。另一方面,firebase 身份验证的实施速度非常快。
TL;DR; Firebase > 认知
我们首先从 Cognito 开始,但我们最终意识到它在使用联合身份(例如,Google 登录、Facebook 登录等)时有一种难闻的气味。对于 Cognito 用户池(即允许用户使用用户名和密码签署 up/in),您可以使用内置的 API Gateway Cognito 用户池授权器,它工作得很好。您不需要编写自己的自定义授权器或任何东西。
但是,如果您想支持联合身份,则需要将 API 网关上的身份验证更改为 IAM Auth,然后让每个客户端 sigv4 对请求进行签名,结果证明这是一个棘手的问题在我们这边,花费了大量的开发时间。选项 2 是让 API Gateway 为每个客户端的 API 调用生成代码...在我看来,这证明了与 Cognito 的繁琐集成。
我们通过 API 网关的自定义授权器让 Firebase 正常工作。对所有客户端(iOS、Android 和 Web)来说都是轻而易举的事。 API 网关端点链接到 Lambda 函数,这些函数能够代表调用端点的用户与 DynamoDB、S3 和其他 Web 服务进行通信。 lambda 函数知道调用用户是谁,因为自定义授权方在 JWT 中返回了电子邮件地址。
这是一个非常基本的 Firebase 自定义授权方,returns 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 网关映射模板中使用 $context.authorizer.principalId
来检索电子邮件并将其传递给 lambda X。
我最初认为延迟会是一个问题,但事实似乎并非如此。我遇到的所有延迟都是由于冷启动导致调用的 lambda 延迟造成的。我注意到授权 lambda 的寿命比其他 lambda 长得多。
每个后端请求都会调用此 lambda。不过有几件事:
- 为每个 JWT 启用 1 小时的缓存,从而大大简化了调用。
- lambda 不断被调用,所以不应该冷启动,而且
- 前一百万 lambda requests/month 免费,之后每百万 requests/month 0.20 美元。因此,除非您的 API 每月被呼叫十亿次,否则您不会产生高得离谱的费用。
以防万一您使用的是 Unity,目前 Unity SDK 不支持 Cognito 用户池。 (也就是AWS托管的用户列表)我目前正因此而犹豫不决。看到我的 post 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 美元 https://aws.amazon.com/cognito/pricing/)
还有一点,在我看来,AWS .NET documentation 对 read/search 来说是一场噩梦。
对我来说,如果您决定转移到其他身份验证服务提供商,交易破坏者能够导出用户的所有详细信息。
虽然这在 Firebase 中可行,但在 AWS Cognitio 中不可用! 您可以在一年中的任何时间进入,但您永远不能离开 :)。 https://forums.aws.amazon.com/thread.jspa?threadID=296932