[AWS] Amazon Cognito
初步认知
一、基本概念
看懂 [AWS] User management and [AWS] OAuth2.0 才方便看到此篇。
Ref: 常见 Amazon Cognito 场景
Amazon Cognito 的两个主要组件:用户池、身份池。
-
- 用户池:是为您的应用程序提供注册和登录选项的用户目录。
- 身份池:提供 AWS 凭证以向用户授予对其他 AWS 服务的访问权限。
-
在第一步中,您的应用程序用户通过用户池登录,并在成功进行身份验证后收到持有者令牌。[access token, id token, refresh token]
-
接下来,您的应用程序通过身份池用用户池令牌交换 AWS 凭证。
-
最后,您的应用程序用户可以使用这些 AWS 凭证 来访问其他 AWS 服务 (如 Amazon S3 或 DynamoDB)。
-
二、使用 “用户池” 进行身份验证
Figure, 标准化推荐访问验证
您可以允许您的用户使用用户池进行身份验证。
您的用户可以通过用户池直接登录,
也可以通过第三方身份提供商 (IdP) 间接登录。
用户池管理处理以下令牌的开销:
从通过 Facebook、Google 和 Amazon 进行的社交登录返回的令牌,
以及从提供单点登录解决方案 (如 Microsoft Active Directory Federation Services (ADFS)) 的 SAML 身份提供商返回的令牌。
成功进行身份验证后,您的 Web 或移动应用程序将收到来自 Amazon Cognito 的持有者令牌。
您可以使用这些令牌检索允许您的应用程序访问其他 AWS 服务的 AWS 凭证,
也可以选择使用它们来控制对您自己的资源或 Amazon API Gateway 的访问。
三、使用用户池访问您自己的资源
您可以允许您的用户使用来自成功的、身份验证的、用户池令牌访问您自己的资源。
有关更多信息,请参阅 用户池身份验证流程 和 将令牌与用户池结合使用。
Figure, 访问自己的资源
用户池身份验证流程
-
- 客户端身份验证流程
- 服务器身份验证流程
- 自定义身份验证流程 ----> 三大令牌
- 管理员身份验证流程
- 用户迁移身份验证流程
将令牌与用户池结合使用
成功进行身份验证后,您的 Web 或移动应用程序将收到来自 Amazon Cognito 的持有者令牌。
以下是由 OpenID Connect 规范定义的令牌:
-
ID 令牌
-
访问令牌
-
刷新令牌
四、使用 ID 令牌
ID 令牌以 JSON Web Token (JWT) 表示。
该令牌包含有关已验证用户的身份的声明。
例如,它包含 name
、family_name
、phone_number
等声明。
有关标准声明的更多信息,请参阅 OpenID Connect 规范。客户端应用程序可以在应用程序中使用此身份信息。
此外,ID 令牌还可用于针对资源服务器或服务器应用程序对用户进行身份验证。
在应用程序外部将 ID 令牌用于 Web API 时,您必须先验证 ID 令牌的签名,然后才能信任 ID 令牌内的任何声明。
ID 令牌会在用户进行身份验证后的 1 小时内过期。在 ID 令牌过期后,您不应该在客户端或 Web API 中对其进行处理。
五、使用 ACCESS 令牌
访问令牌也以 JSON Web Token (JWT) 表示。它也包含有关已验证用户的声明,但与 ID 令牌不同,它不包含用户的所有身份信息。
访问令牌的主要用途是在用户池中用户的环境中授予操作权限。
例如,您可以根据用户池使用访问令牌更新或删除用户属性。
此外,访问令牌还可与任何 Web API 结合使用,以做出访问控制决策并在用户环境中授予操作权限。
与 ID 令牌一样,您必须先在 Web API 中验证访问令牌的签名,然后才能信任访问令牌内的任何声明。
访问令牌会在用户进行身份验证后的 1 小时内过期。在访问令牌过期后,您不应该对其进行处理。
六、使用刷新令牌
要使用刷新令牌获取新令牌,请使用 InitiateAuth 或 AdminInitiateAuth API 方法。验证流程类型为 REFRESH_TOKEN_AUTH。授权参数 AuthParameters
是密钥-值映射,其中密钥为“REFRESH_TOKEN”,值为实际刷新令牌。
这会通过 Amazon Cognito 服务器启动令牌刷新流程并返回新的 ID 和访问令牌。
默认情况下,刷新令牌会在用户进行身份验证后的 30 天内过期。当您为用户池创建应用程序时,您可以将应用程序的 Refresh token expiration (days) 设置为介于 1 和 3650 之间的任何值。
问题来了,如何让另一个独立的服务纳入到现有的用户认证系统中来?
AWS 提供的单点登录(SSO)
一、为什么使用SSO
From: https://www.jianshu.com/p/613e44d4a464
单点登录SSO(Single Sign On)说得简单点就是在一个多系统共存的环境下,用户在一处登录后,就不用在其他系统中登录,也就是用户的一次登录能得到其他所有系统的信任。
单点登录在大型网站里使用得非常频繁,例如像阿里巴巴这样的网站,在网站的背后是成百上千的子系统,用户一次操作或交易可能涉及到几十个子系统的协作,如果每个子系统都需要用户认证,不仅用户会疯掉,各子系统也会为这种重复认证授权的逻辑搞疯掉。
实现单点登录说到底就是要解决如何产生和存储那个信任,再就是其他系统如何验证这个信任的有效性,因此要点也就以下两个:
-
- 存储信任
- 验证信任
二、解决方案
-
以Cookie作为凭证媒介【安全有风险】
最简单的单点登录实现方式,是使用cookie作为媒介,存放用户凭证。
用户登录父应用之后,应用返回一个加密的cookie,当用户访问子应用的时候,携带上这个cookie,授权应用解密cookie并进行校验,校验通过则登录当前用户。
-
通过JSONP实现【有安全风险】
对于跨域问题,可以使用JSONP实现。
-
通过页面重定向的方式
最后一种介绍的方式,是通过 "父应用" 和 "子应用" 来回重定向中进行通信,实现信息的安全传递。
父应用提供一个GET方式的登录接口,
用户通过子应用重定向连接的方式访问这个接口,
-- 如果用户还没有登录,则返回一个的登录页面,用户输入账号密码进行登录。
-- 如果用户已经登录了,则生成加密的Token,并且重定向到子应用提供的验证Token的接口,通过解密和校验之后,子应用登录当前用户。
这种方式较前面两种方式,接解决了上面两种方法暴露出来的安全性问题和跨域的问题,但是并没有前面两种方式方便。
安全与方便,本来就是一对矛盾。
随之而来的问题:上图中Figure 01, 我拿什么来作为重定向的请求?
More details: 单点登录系统(SSO)-总结
More details: SSO单点登录三种情况的实现方式详解
这里实际出现了问题,两个端口需要一个统一的http server来分流,统一作为“前台”接待用户。
在此项目中不适合。
SSO讨论到此为止。
AWS Amplify
一、是什么
Goto:Quick Start
AWS Amplify 库模块分为许多类别(授权、分析、存储、API、缓存),可快速添加用户注册/登录、MFA、跟踪或指标分析、内容管理或无服务器 API 集成等功能。
总而言之,一个集成化的工具集,开发可扩展的移动和 Web 应用程序的最快捷、最简单方法。
二、安装 amplify
$ npm install --save aws-amplify
# On a React app, in addition to aws-amplify,
# we provide helpers and higher order components that are packaged in aws-amplify-react. $ npm install --save aws-amplify-react # optional HOCs
[AWS] OAuth2.0
Ref: 理解OAuth 2.0
若干专有名词:
(1)Third-party application:第三方应用程序,本文中又称"客户端"(client),即上一节例子中的"云冲印"。
(2)HTTP service: HTTP服务提供商,本文中简称"服务提供商",即上一节例子中的Google。
(3)Resource Owner: 资源所有者,本文中又称"用户"(user)。
(4)User Agent: 用户代理,本文中就是指 浏览器。
(5)Authorization server: 认证服务器,即服务提供商专门用来处理认证的服务器。
(6)Resource server: 资源服务器,即服务提供商存放用户生成的资源的服务器。它与认证服务器,可以是同一台服务器,也可以是不同的服务器。
上图第三步中的“授权”,可以是,比如“授权码” + “重定向URI”。
(A)用户打开客户端以后,客户端要求用户给予授权。
(B)用户同意给予客户端授权。 # 最为重要 --> 详解
(C)客户端使用上一步获得的授权,向认证服务器申请令牌。
(D)认证服务器对客户端进行认证以后,确认无误,同意发放令牌。
(E)客户端使用令牌,向资源服务器申请获取资源。
(F)资源服务器确认令牌无误,同意向客户端开放资源。
客户端必须得到用户的授权(authorization grant),才能获得令牌(access token)。
OAuth 2.0定义了四种授权方式。
- 授权码模式(authorization code) # 功能最完整、流程最严密的授权模式
- 简化模式 (implicit)
- 密码模式 (resource owner password credentials)
- 客户端模式(client credentials)
资源服务器如何辨别令牌的真假?
因为有一步可能是在客户端的后端的服务器上完成的,对用户不可见。详情如下:
授权码模式
(A)用户访问客户端,后者将前者导向认证服务器。客户端申请认证的URI,包含以下参数:
-
- response_type:表示授权类型,必选项,此处的值固定为"code"
- client_id: 表示客户端的ID,必选项
- redirect_uri: 表示重定向URI,可选项
- scope: 表示申请的权限范围,可选项
- state: 表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
GET /authorize?response_type=code&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
(B)用户选择是否给予客户端授权。 (C)假设用户给予授权,认证服务器将用户导向客户端事先指定的"重定向URI"(redirection URI),同时附上一个授权码。回应URI:
-
- code: 表示授权码,必选项。
该码的有效期应该很短,通常设为10分钟,客户端只能使用该码一次,否则会被授权服务器拒绝。
该码与客户端ID和重定向URI,是一一对应关系。
-
- state:如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
HTTP/1.1 302 Found
Location: https://client.example.com/cb?code=SplxlOBeZQQYbYS6WxSbIA
&state=xyz
(D)客户端收到授权码,附上早先的"重定向URI",向认证服务器申请令牌。这一步是在客户端的后台的服务器上完成的,对用户不可见。
-
- grant_type: 表示使用的授权模式,必选项,此处的值固定为"authorization_code"。
- code: 表示上一步获得的授权码,必选项。
- redirect_uri:表示重定向URI,必选项,且必须与A步骤中的该参数值保持一致。
- client_id: 表示客户端ID,必选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code&code=SplxlOBeZQQYbYS6WxSbIA
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb
(E)认证服务器核对了授权码和重定向URI,确认无误后,向客户端发送访问令牌(access token)和更新令牌(refresh token)。
-
- access_token: 表示访问令牌,必选项。
- token_type: 表示令牌类型,该值大小写不敏感,必选项,可以是bearer类型或mac类型。
- expires_in: 表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- refresh_token:表示更新令牌,用来获取下一次的访问令牌,可选项。
- scope: 表示权限范围,如果与客户端申请的范围一致,此项可省略。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
简化模式
简化模式(implicit grant type)不通过第三方应用程序的服务器,直接在浏览器中向认证服务器申请令牌,
跳过了"授权码"这个步骤,因此得名。所有步骤在浏览器中完成,令牌对访问者是可见的,且客户端不需要认证。
(A)客户端将用户导向认证服务器。
-
- response_type:表示授权类型,此处的值固定为"token",必选项。
- client_id: 表示客户端的ID,必选项。
- redirect_uri: 表示重定向的URI,可选项。
- scope: 表示权限范围,可选项。
- state: 表示客户端的当前状态,可以指定任意值,认证服务器会原封不动地返回这个值。
GET /authorize?response_type=token&client_id=s6BhdRkqt3&state=xyz
&redirect_uri=https%3A%2F%2Fclient%2Eexample%2Ecom%2Fcb HTTP/1.1
Host: server.example.com
(B)用户决定是否给于客户端授权。 (C)假设用户给予授权,认证服务器将用户导向客户端指定的"重定向URI",并在URI的Hash部分包含了访问令牌。
[简化去掉了“授权码”,直接获得了隐藏在hash值中的令牌,浏览器此时没法提取令牌]
-
- access_token:表示访问令牌,必选项。
- token_type: 表示令牌类型,该值大小写不敏感,必选项。
- expires_in: 表示过期时间,单位为秒。如果省略该参数,必须其他方式设置过期时间。
- scope: 表示权限范围,如果与客户端申请的范围一致,此项可省略。
- state: 如果客户端的请求中包含这个参数,认证服务器的回应也必须一模一样包含这个参数。
HTTP/1.1 302 Found Location: http://example.com/cb#access_token=2YotnFZFEjr1zCsicMWpAA &state=xyz&token_type=example&expires_in=3600
(D)浏览器向资源服务器发出请求,其中不包括上一步收到的Hash值。
(E)资源服务器返回一个网页,其中包含的代码可以获取Hash值中的令牌。
(F)浏览器执行上一步获得的脚本,提取出令牌。
(G)浏览器将令牌发给客户端。
密码模式
在这种模式中,用户必须把自己的密码给客户端,但是客户端不得储存密码。
这通常用在用户对客户端高度信任的情况下,比如客户端是操作系统的一部分,或者由一个著名公司出品。
而认证服务器只有在其他授权模式无法执行的情况下,才能考虑使用这种模式。
整个过程中,客户端不得保存用户的密码。
(A)用户向客户端提供用户名和密码。
(B)客户端将用户名和密码发给认证服务器,向后者请求令牌。
-
- grant_type:表示授权类型,此处的值固定为"password",必选项。
- username: 表示用户名,必选项。
- password: 表示用户的密码,必选项。
- scope: 表示权限范围,可选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=password&username=johndoe&password=A3ddj3w
(C)认证服务器确认无误后,向客户端提供访问令牌。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"refresh_token":"tGzv3JOkF0XG5Qx2TlKWIA",
"example_parameter":"example_value"
}
客户端模式
客户端模式(Client Credentials Grant)指客户端以自己的名义,而不是以用户的名义,向"服务提供商"进行认证。
严格地说,客户端模式并不属于OAuth框架所要解决的问题。
在这种模式中,用户直接向客户端注册,客户端以自己的名义要求"服务提供商"提供服务,其实不存在授权问题。
(A)客户端向认证服务器进行身份认证,并要求一个访问令牌。客户端发出的HTTP请求,包含以下参数:
-
- granttype:表示授权类型,此处的值固定为"clientcredentials",必选项。
- scope:表示权限范围,可选项。
POST /token HTTP/1.1
Host: server.example.com
Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW
Content-Type: application/x-www-form-urlencoded
grant_type=client_credentials
(B)认证服务器确认无误后,向客户端提供访问令牌。
HTTP/1.1 200 OK
Content-Type: application/json;charset=UTF-8
Cache-Control: no-store
Pragma: no-cache
{
"access_token":"2YotnFZFEjr1zCsicMWpAA",
"token_type":"example",
"expires_in":3600,
"example_parameter":"example_value"
}
更新令牌
如果用户访问的时候,客户端的"访问令牌"已经过期,则需要使用"更新令牌"申请一个新的访问令牌。
客户端发出更新令牌的HTTP请求,包含以下参数:
granttype: 表示使用的授权模式,此处的值固定为"refreshtoken",必选项。 refresh_token:表示早前收到的更新令牌,必选项。 scope: 表示申请的授权范围,不可以超出上一次申请的范围,如果省略该参数,则表示与上一次一致
下面是一个例子。
POST /token HTTP/1.1 Host: server.example.com Authorization: Basic czZCaGRSa3F0MzpnWDFmQmF0M2JW Content-Type: application/x-www-form-urlencoded grant_type=refresh_token&refresh_token=tGzv3JOkF0XG5Qx2TlKWIA