aws cognito
Handling auth is painful. But most applications need to authenticate users and control what resources they can access. Microservices, though growing in popularity, can add complexity. You need to secure both the user’s actions and the interactions between services.
处理身份验证很痛苦。 但是大多数应用程序需要对用户进行身份验证并控制他们可以访问哪些资源。 微服务尽管越来越流行,但会增加复杂性。 你需要确保这两个用户的操作和服务之间的交互。
AWS offers some great building blocks for a microservices architecture. But like furniture from IKEA, you have to assemble the pieces yourself. Plus the instructions aren’t very good.
AWS为微服务架构提供了一些出色的构建块。 但是,就像宜家的家具一样,您必须自己组装。 再加上说明不是很好。
We’ll build a simple application and configure AWS to authenticate a user and secure a microservice.
我们将构建一个简单的应用程序,并将AWS配置为对用户进行身份验证并保护微服务。
TL; DR(不耐烦) (TL;DR (for the impatient))
Working Demo: https://auth-api-demo.firebaseapp.com/ (user: demouser
password: demoPASS123)
工作演示: https://auth-api-demo.firebaseapp.com/ (用户: demouser
密码: demoPASS123)
GitHub Repo: https://github.com/csepulv/auth-api-demo
GitHub存储库 : https : //github.com/csepulv/auth-api-demo
Base Use Case/Assumption: There are two groups of resources — a) those that need an authenticated user and b) those that do not.
基本用例/假设:有两类资源-a )需要认证用户的资源, b)不需要资源的资源。
We’ll use
我们将使用
AWS Lambda, API Gateway, and Cognito
Claudia.js (for building our API)
Claudia.js (用于构建我们的API)
React (for our web client)
React (针对我们的Web客户端)
For those who read till the end, there are some goodies.
对于那些读到最后的人,有一些好东西。
Now, for the details.
现在,了解详细信息。
概念应用模型 (Conceptual Application Model)
The demo application implements the following model.
该演示应用程序实现以下模型。
- A user signs into an application and gets an authentication token 用户登录应用程序并获取身份验证令牌
- AWS uses this token to verify identity and to authorize user requests for protected resources AWS使用此令牌来验证身份并授权用户对受保护资源的请求
the App Gateway creates a virtual moat between users and application resources
App Gateway在用户和应用程序资源之间创建了一条虚拟的护城河
AWS服务 (AWS Services)
If you are new to AWS, there is the official AWS Getting Started portal. Also, Udemy has a free course, AWS Essentials.
如果您不熟悉AWS,则有官方的AWS入门门户。 此外,Udemy还提供免费课程AWS Essentials 。
You will need access to an AWS account. You can signup for the AWS free tier.
您将需要访问一个AWS账户。 您可以注册AWS 免费套餐 。
AWS Lambda (AWS Lambda)
While EC2 is one of the most popular AWS options, I think Lambda is better suited to microservices. EC2 instances are virtual machines. You are responsible for everything from the operating system to all the software it runs. Lambda is a Function as a Service model. There is no server provisioning or deployment; you write your service logic.
尽管EC2是最受欢迎的AWS选项之一,但我认为Lambda更适合微服务。 EC2实例是虚拟机。 您要负责从操作系统到其运行的所有软件的所有工作。 Lambda是功能即服务模型。 没有服务器配置或部署; 您编写服务逻辑。
For more info, refer to the AWS Lambda docs.
有关更多信息,请参阅AWS Lambda文档 。
But there is a wrinkle with Lambdas. They can’t be directly reached by an application user. Lambdas need triggers that invoke the Lambda function. This can be a queued message, or in our case, an API gateway request.
但是Lambdas会有皱纹。 应用程序用户无法直接访问它们。 Lambda需要触发器来调用Lambda函数。 这可以是排队的消息,在我们的情况下可以是API网关请求。
AWS API网关 (AWS API Gateway)
An API gateway provides a moat around your application services. It can log user activity, authenticate requests and enforce usage policies (like rate limiting). (The AWS API Gateway docs are a good reference.)
API网关为您的应用程序服务提供了便利。 它可以记录用户活动,验证请求并执行使用策略(例如速率限制)。 ( AWS API Gateway文档是一个很好的参考。)
AWS Cognito (AWS Cognito)
AWS Cognito is a user management, authentication, and access control service. Unfortunately, all the features and configuration can be confusing at times. (As if security and authentication were ever easy. ? ) We will focus on the core elements of Cognito for securing our API.
AWS Cognito是一项用户管理,身份验证和访问控制服务。 不幸的是,所有功能和配置有时会令人困惑。 (好像安全性和身份验证曾经是一件容易的事。?)我们将专注于Cognito的核心元素来保护我们的API。
应用程序和环境设置 (Application and Environment Setup)
The recipe for our demo application is:
我们的演示应用程序的配方是:
- In AWS Cognito, create a User Pool (with a client application) and a Federated Identity Pool. 在AWS Cognito中,创建一个用户池(带有客户端应用程序)和一个联合身份池。
- In AWS API Gateway, create a usage plan and API key 在AWS API Gateway中,创建使用计划和API密钥
- Using Claudia JS, build and deploy a simple AWS Lambda-based API. 使用Claudia JS,构建和部署简单的基于AWS Lambda的API。
- Update AWS IAM role to grant authenticated users access to protected API methods 更新AWS IAM角色以授予经过身份验证的用户访问受保护的API方法的权限
Create a single page app (SPA) using
create-react-app
. It will use AWS Cognito and makes signed (and authenticated) API requests使用
create-react-app
创建一个单页应用(SPA)。 它将使用AWS Cognito并发出签名(和经过身份验证)的API请求
The detailed AWS setup is in aws-setup.md
, in the demo GitHub repo. We’ll highlight aspects of the setup and explain things work.
详细的AWS设置位于演示GitHub存储库中的aws-setup.md
中。 我们将重点介绍设置的各个方面,并说明工作原理。
AWS Cognito (AWS Cognito)
User Pool, Client Application, and Domain Name
用户池,客户端应用程序和域名
We’ll create a User Pool with the defaults. Details and screenshots:
我们将使用默认值创建一个用户池。 详细信息和屏幕截图:
Federated Identity Pool
联合身份库
It may be a little confusing that we need both a User Pool and a Federated Identity Pool. Ashan Fernando has a pretty good explanation in this post. Put simply,
我们既需要用户池又需要联合身份池,这可能会有点令人困惑。 Ashan Fernando在这篇文章中有一个很好的解释。 简单地说,
User Pools provide access for a user to an application. This is like services such as Auth0.
用户池为用户提供了对应用程序的访问。 这就像Auth0之类的服务。
A Federated Identity Pool provides access to AWS resources.
联合身份池提供对AWS资源的访问。
By combining the two pools, our application can authenticate a user and AWS will assign temporary credentials. These credentials allow the user to access AWS resources. The IAM role, configured in the Identity Pool, specifies the privileges for the temporary credentials.
通过组合两个池,我们的应用程序可以对用户进行身份验证,AWS将分配临时凭证 。 这些凭证允许用户访问AWS资源。 在身份池中配置的IAM角色指定临时凭据的特权。
The detailed Federated Identity Pool setup is here.
详细的联合身份池设置在此处 。
AWS API网关 (AWS API Gateway)
I suggest creating a usage plan for our API. While not a requirement, it is a good practice, as AWS costs can “run away” if you aren’t careful. We will create a Usage Plan, named api-auth-demo
and set a throttle and burst rate, and a daily quota for API calls. We will also create an API key, which the web client application will use. (Full setup details are here.)
我建议为我们的API创建一个使用计划。 虽然不是必需的,但这是一个好习惯,因为如果您不小心,AWS成本可能会“消失”。 我们将创建一个名为api-auth-demo
的使用计划 ,并设置限制和突发速率以及API调用的每日配额。 我们还将创建一个API密钥,供Web客户端应用程序使用。 (完整的设置详细信息在这里 。)
We’ve finished the bulk of our AWS setup. We will now write our Lambda functions and then build our React web application.
我们已经完成了大部分的AWS设置。 现在,我们将编写Lambda函数,然后构建我们的React Web应用程序。
AWS Lambda和Claudia JS (AWS Lambda and Claudia JS)
We will write our Lambda functions using Node.js. Claudia.js will deploy our Lambdas and configure the API Gateway. (As a note, the Serverless framework provides similar functionality.)
我们将使用Node.js编写Lambda函数。 Claudia.js将部署我们的Lambda,并配置API网关。 (请注意, 无服务器框架提供了类似的功能。)
We only need a simple API for our example. We’ll create two API methods (i.e. very simple microservices): one for authenticated users and one for guests.
对于我们的示例,我们只需要一个简单的API。 我们将创建两种API方法(即非常简单的微服务):一种用于经过身份验证的用户,另一种用于访客。
We’ll use the Claudia API Builder, which lets multiple routes map to a single lambda. The routing mechanism is similar to routing in frameworks such as Express.js.
我们将使用Claudia API Builder ,它可以将多个路由映射到单个lambda。 路由机制类似于Express.js之类的框架中的路由。
const ApiBuilder = require("claudia-api-builder");
const api = new ApiBuilder();
api.get("/no-auth",request => {
return {message: "Open for All!"};
},
{ apiKeyRequired: true }
);
api.get("/require-auth", request => {
return {message: "You're past the velvet rope!"};
},
{ apiKeyRequired: true, authorizationType: "AWS_IAM" }
);
module.exports = api;
view rawapi.js hosted with ❤ by GitHub
We’ll use the Claudia.js command line to deploy the API to AWS.
我们将使用Claudia.js 命令行将 API部署到AWS。
claudia create --region us-west-2 --api-module api --name auth-api-demo
NOTE: Any changes to api.js
will need to be re-deployed. Useclaudia update...
注意:对api.js
任何更改都需要重新部署。 使用claudia update...
API Keys and Auth
API密钥和验证
In api.js
, {apiKeyRequired: true}
indicates that API requests require an API key. {authorizationType: 'AWS_IAM'}
configures the API Gateway to authorize using AWS IAM. The underlying authentication mechanism is not obvious. The AWS docs outline the approach, but a summary is:
在api.js
, {apiKeyRequired: true}
表示API请求需要API密钥。 {authorizationType: 'AWS_IAM'}
将API网关配置为使用AWS IAM进行授权。 底层的身份验证机制并不明显。 AWS文档概述了该方法,但摘要为:
when a user signs in, Cognito will issue tokens for temporary credentials (obtained via STS).
当用户登录时,Cognito将为临时凭证(通过STS获得)颁发令牌。
- for protected resources, the application needs to sign requests using these credentials 对于受保护的资源,应用程序需要使用这些凭据对请求进行签名
- AWS decodes and verifies the signature AWS解码并验证签名
- if the signature is valid, the API Gateway dispatches the request 如果签名有效,API网关将分派请求
There are other authorization methods available. The Claudia.js docs outline how to specify other methods. (The corresponding AWS docs are here.)
还有其他授权方法。 Claudia.js 文档概述了如何指定其他方法。 (相应的AWS文档在这里 。)
身份验证用户的AWS IAM角色 (AWS IAM Roles for Authenticated Users)
We need to edit the privileges for the IAM roles for authenticated users. We need to allow invoking the API Gateway method we created.
我们需要为经过身份验证的用户编辑IAM角色的特权。 我们需要允许调用我们创建的API Gateway方法。
We need the ARN of the API Gateway. Go to the API Gateway console and find the API Gateway resource/method.
我们需要API网关的ARN 。 转到API Gateway控制台并找到API Gateway资源/方法。
- Copy the ARN 复制ARN
Go to the IAM console and find the Authenticated role created during the Cognito Federated Identity Pool setup
转到IAM控制台,找到在Cognito联合身份池设置期间创建的Authenticated角色。
add an Inline Policy as below
如下添加一个内联策略
- Specify the copied ARN for the API Gateway resource in the policy. 在策略中为API网关资源指定复制的ARN。
Authenticated users can now invoke our protected API methods.
经过身份验证的用户现在可以调用我们受保护的API方法。
服务到服务访问控制 (Service to Service Access Control)
The Cognito setup will allow a user to invoke an API method. But this method invocation is a trigger for a Lambda function. The Lambda function executes within the context of a different IAM role. It is no longer a direct user request, but an AWS service to service interaction. IAM roles provide access control for this interaction.
Cognito设置将允许用户调用API方法。 但是,此方法调用是Lambda函数的触发器。 Lambda函数在其他IAM角色的上下文中执行。 它不再是直接的用户请求,而是一个AWS服务到服务的交互。 IAM角色为此交互提供访问控制。
Claudia.JS created the IAM role for the Lambda function. (You can also manually create this role and specify its identifier to Claudia.JS via the --role
parameter. Details are here.)
Claudia.JS为Lambda函数创建了IAM角色。 (您也可以手动创建此角色,并通过--role
参数将其标识符指定给Claudia.JS。 此处有详细信息。)
If our Lambda function needs access to other AWS resources, we will need to update the Lambda’s IAM role and provide these privileges. This might be an RDS database, for example.
如果我们的Lambda函数需要访问其他AWS资源,我们将需要更新Lambda的IAM角色并提供这些特权。 例如,这可能是RDS数据库。
AWS has always used IAM to configure service to service access control. It is a well developed and well-documented model. It will probably be your primary mechanism for access control between microservices (within AWS). There might be cases where you need to augment or replace it, but I would start with IAM.
AWS一直使用IAM来配置服务到服务访问控制。 这是一个完善且文档完善的模型。 这可能是您在微服务之间(在AWS内)进行访问控制的主要机制。 在某些情况下,您需要增加或替换它,但从IAM开始。
We can now build the web application for our users.
现在,我们可以为我们的用户构建Web应用程序。
React Web应用程序 (React Web Application)
I am going to build a React single page web application (SPA). A Vue.js or Angular application would work too. For the client application, there are two significant components: AWS Amplify and the aws4
module.
我将构建一个React单页Web应用程序(SPA)。 Vue.js或Angular应用程序也可以工作。 对于客户端应用程序,有两个重要组件: AWS Amplify和aws4
模块。
AWS Amplify provides easy integration with AWS Cognito. aws4
is a popular library for signing AWS requests using AWS Request Signatures Version 4. AWS used signed requests for protected resources (i.e. authorized user requests).
AWS Amplify提供了与AWS Cognito的轻松集成。 aws4
是一个流行的库,用于使用AWS Request Signatures Version 4签署AWS请求。 AWS使用签署的受保护资源请求(即授权用户请求)。
Returning to the web client, we’ll use create-react-app
. I won't outline the steps, as they are well documented on the create-react-app
home page, and there are numerous online tutorials. (I've even written a few. )
返回到Web客户端,我们将使用create-react-app
。 我不会概述这些步骤,因为在create-react-app
主页上已对这些步骤进行了详细记录,并且有许多在线教程。 (我什至写了一些 。)
For authentication, we need to do some state management. The example application doesn’t use any framework, but in a real application I’d suggest Mobx (or Redux.)
对于身份验证,我们需要进行一些状态管理。 示例应用程序不使用任何框架,但是在实际应用程序中,我建议使用Mobx (或Redux) 。
In the demo application, auth-store.js
manages the user authentication state. This consists of the user's authentication state and credentials. These are used to
在演示应用程序中, auth-store.js
管理用户身份验证状态。 这由用户的身份验证状态和凭据组成。 这些习惯于
- render different components and styles for authenticated vs. guest user 为经过身份验证的用户与来宾用户呈现不同的组件和样式
- sign requests for protected API methods 签署受保护的API方法的请求
While AWS Amplify manages much of the AWS Cognito integration, there is some work for us to do.
尽管AWS Amplify管理着许多AWS Cognito集成,但仍有一些工作要做。
Determining Auth State from AWS Amplify
从AWS Amplify确定身份验证状态
AWS Amplify’s documentation is good in some areas and deficient in others. I suggest reading the Authentication section of the Amplify documentation. This describes theAuth
component, which interacts with Cognito.
AWS Amplify的文档在某些方面是好的,而在其他方面则是不足的。 我建议阅读Amplify文档的Authentication部分 。 这描述了与Cognito交互的Auth
组件。
However, there are still some aspects that the documentation doesn’t clearly address. AWS Amplify doesn’t make it easy to know the authentication state. (A discussion of this complexity is here.) Amplify configures itself asynchronously, without a callback. But there is an aws-amplify
class that can help.
但是,仍有一些方面文档未明确解决。 AWS Amplify很难让您轻松了解身份验证状态。 ( 这里讨论了这种复杂性。)Amplify异步配置自身,没有回调。 但是有一个aws-amplify
类可以提供帮助。
The Hub
class in the aws-amplify
module behaves like an event emitter. We care about two events: configured
and cognitoHostedUI
.
aws-amplify
模块中的Hub
类的行为类似于事件发射器。 我们关心两个事件: configured
和cognitoHostedUI
。
After the AWS Amplify configures the Auth
component, it emits the configured
event. Our application can then inquire about the current user's authentication status. This is useful when our application is being loaded, for example.
AWS Amplify配置Auth
组件后,它将发出已configured
事件。 然后,我们的应用程序可以查询当前用户的身份验证状态。 例如,这在加载我们的应用程序时很有用。
While using the application, we need to know if the authentication state changes. There is a sign-in
event, but it isn't the event we want, as our demo application uses OAuth and the Cognito Hosted UI. The sign-in
event is used in a custom sign-in/up screen or when using the built-in Amplify React UI. For OAuth, Amplify dispatches the cognitoHostedUI
event after a completed OAuth sign-in flow.
在使用该应用程序时,我们需要知道身份验证状态是否更改。 有一个sign-in
事件,但这不是我们想要的事件,因为我们的演示应用程序使用OAuth和Cognito Hosted UI 。 sign-in
事件用于自定义登录/注册屏幕或使用内置的Amplify React UI时。 对于OAuth,Amplify在完成OAuth登录流程后调度cognitoHostedUI
事件。
Signing Requests
签署要求
The current user will have credentials issued by AWS Cognito. These contain an access id, a secret key, and a session key. These are available by calling Auth.currentCredentials()
in aws-amplify
. For API methods authorized by IAM, you need to sign the request using AWS V4 Request Signatures. Thankfully, the aws4
module handles the complexities of generating these signatures.
当前用户将具有AWS Cognito颁发的凭证。 它们包含一个访问ID ,一个秘密密钥和一个会话密钥 。 这些可以通过在aws-amplify
调用Auth.currentCredentials()
来aws-amplify
。 对于由授权的IAM API方法,您需要注册使用请求AWS V4请求签名 。 值得庆幸的是, aws4
模块处理了生成这些签名的复杂性。
In api-client.js
,
import aws4 from "aws4";
const apiHost = process.env.REACT_APP_API_HOST;
const apiKey = process.env.REACT_APP_API_KEY;
const region = process.env.REACT_APP_REGION;
export async function authenticatedCall(authStore) {
const opts = {
method: "GET",
service: "execute-api",
region: region,
path: "/latest/require-auth",
host: apiHost,
headers: { "x-api-key": apiKey },
url: `https://${apiHost}/latest/require-auth`
};
const credentials = await authStore.getCredentials();
const { accessKeyId, secretAccessKey, sessionToken } = credentials;
const request = aws4.sign(opts, {
accessKeyId,
secretAccessKey,
sessionToken
});
delete request.headers.Host;
const response = await fetch(opts.url, {
headers: request.headers
});
if (response.ok) {
return await response.json();
} else return { message: response.statusText };
}
export async function noAuthCall(authStore) {
const response = await fetch(`https://${apiHost}/latest/no-auth`, {
headers: { "x-api-key": apiKey }
});
return await response.json();
}
view rawapi-client.js hosted with ❤ by GitHub
演示版 (Demo)
We can finally run npm start
and run the app! When we first arrive at the application, we are a guest (unauthenticated user). You can also go to https://auth-api-demo.firebaseapp.com/ to try it out.
我们终于可以运行npm start
并运行该应用程序了! 当我们第一次到达该应用程序时,我们是访客(未经身份验证的用户)。 您也可以访问https://auth-api-demo.firebaseapp.com/进行尝试。
We can access unprotected methods.
我们可以访问不受保护的方法。
But if we try to access a protected resource, it will fail.
但是,如果我们尝试访问受保护的资源,它将失败。
But if we sign in, we can access the protected resources.
但是,如果我们登录,则可以访问受保护的资源。
Click Sign In and use demouser
with password of demoPASS123
.
点击登录并使用demouser
与密码demoPASS123
。
We can now click the Req. Auth
button to access a protected API method.
现在,我们可以单击“ Req. Auth
Req. Auth
按钮以访问受保护的API方法。
Whew! We had to configure multiple services and digest a lot of information. But we now have an application that is a model for authenticating microservices on AWS.
ew! 我们必须配置多种服务并提取大量信息。 但是我们现在有了一个应用程序,该应用程序是用于在AWS上认证微服务的模型。
怎么办? (Now What?)
This article’s approach is “all-in” on AWS. This was a deliberate choice, to show how the various AWS pieces fit together to solve a common need, namely auth. There are alternatives to methods in this article, and I outline a few here.
本文的方法是在AWS上“全力以赴”。 这是一个有意的选择,以显示各种AWS组件如何组合在一起以解决通用需求(即auth)。 本文提供了方法的替代方法,我在这里概述了一些方法。
And for those who stayed with me to the end, I have some parting gifts.
对于那些一直陪伴我到最后的人,我有一些分开的礼物。
In the demo repo, there is a script for automating the AWS setup. Its README has the details for running it.
resources-cheatsheet.md
has the specific links for relevant AWS, Claudia.js, etc. documentation.resources-cheatsheet.md
具有相关AWS,Claudia.js等文档的特定链接。
Thanks for reading!
谢谢阅读!
aws cognito