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。不过有几件事:
- 为每个 JWT 启用 1 小时的缓存,从而大大简化了调用。
- 不断调用 lambda,因此不应出现冷启动,并且
- 前一百万个 lambda 请求/月是免费的,之后每百万个请求/月是 0.20 美元。因此,除非您的 API 每月调用 BILLION 次,否则您不会产生高昂的成本。