AWS国内版Cognito身份池
概述
AWS Cognito组件用户池(Cognito User Pool)国内暂未上线,身份云竹云IDaaS可完全替代Cognito用户池,借助身份云进行用户身份验证并融合Coginto身份池Identity Pool,实现对AWS资源的无缝安全访问。
本文介绍如何使用 竹云IDaaS OpenID Connect 协议做为用户池(Cognito User Pool)的替代方案。我们将准备一个JavaScript示例demo示例,您可以根据自己的需求进行自定义。本示例主要演示竹云IDaaS作为身份提供者,允许用户使用竹云IDaaS用户名和密码登录,来获取Cognito token。
术语说明
Cognito User Pool: Cognito用户池负责身份验证。最终用户可以通过用户池完成注册和登录过程。
Cognito Identity Pool: Cognito身份池负责授权(访问控制),授予最终用户使用AWS资源的权利。
竹云IDaaS:基于云原生身份云服务平台,可以取代Cognito用户池,在国内用户和AWS资源之间架起一座桥梁,以下简称竹云IDaaS或平台。
身份验证流程

流程说明
用户访问示例demo示例并点击“使用竹云IDaaS登录”按钮。
该demo示例将用户重定向到竹云IDaaS进行登录。成功验证后,该demo示例会从竹云IDaaS接收ID Token。
该demo示例将ID Token交换成Cognito令牌。
该demo示例将Cognito令牌交换成临时AWS安全凭据。
该demo示例使用凭据访问AWS服务。
前提条件
- AWS帐户。如果您没有,您可以免费开始使用AWS。
- 用于托管示例demo示例的web服务器。
竹云IDaaS 配置
登录竹云IDaaS 企业中心【资源】->【应用】->【添加自建应用】,应用名称可以写【Cognito OIDC示例】,认证集成选择【OIDC】。
配置应用认证参数。

- 回调地址:请指定Web服务器上Callback.html文件的路径。示例:https://localhost/callback
- 隐式授权模式:本demo示例需要将隐式授权模式开启,如果您的应用程序是后端和竹云IDaaS集成,您也可以选择关闭隐式授权模式,使用授权码模式,通过授权码来获取 ID Token,以便 Demo 中使用 竹云IDaaS 的 ID Token 交换 Cognito 令牌。
请记住竹云IDaaS应用的 ClientId , 我们将提供给 AWS 作为 OpenId Connect 身份提供商的“受众”。
- 应用左侧菜单栏下切换至 【授权管理】->【应用账号】” 页签,添加账号。
AWS IAM 配置
登录 AWS Console。
在“All services”选择“身份和访问管理(IAM)”。
选择“身份提供商”。

点击“添加提供商”,选择“OpenID Connect”。
填写“提供商 URL”:示例:https://{yourdomain}/api/v1/oauth2, 更换示例中yourdoamin为您的竹云IDaaS域名,点击【获取指纹】。
填写“受众”:您的竹云IDaaS应用的 ClientId,即您在上一步竹云IDaaS 平台建的应用,保存成功。
请记您的提供商名称,因为我们稍后在创建示例demo示例时需要它,示例:{yourdomain}/api/v1/oauth2
AWS Cognito 配置
登录 AWS Console。
在“All services”选择“Cognito”。
选择您的身份池, 如果没有身份池,请“创建身份池”。
配置身份池信任,选择身份来源:OpenID Connect (OIDC),点击“下一步”。

创建IAM角色名称,示例:Cognito_竹云IDaaSAuth_Role。可以查看策略详情,Cognito自动增加GetCredentialsForIdentity权限
{
"Effect": "Allow",
"Action": [
"cognito-identity:GetCredentialsForIdentity"
],
"Resource": [
"*"
]
}- 选择您前面建的身份提供商,点击保存。

请记住身份池ID,因为我们稍后在创建示例demo示例时需要它。
创建示例程序
- demo示例只包含两个文件 — index.html和callback.html。在本节中,我将显示这两个文件的完整代码列表。接下来,您只需要分别更新文件中三个变量,然后将它们部署到您的服务器中。
index.html
index.html文件显示“使用竹云IDaaS登录”按钮,并将用户重定向到竹云IDaaS进行身份验证。此文件是示例demo示例的起点。它需要配置您的应用的 ClientId,这就是竹云IDaaS知道登录请求来自哪个demo示例的方式。
下面列出index.html的完整标记和代码,您还需要以下三步:
替换JavaScript代码中的client_id为您的 ClientId,即您在【竹云IDaaS 配置】获取的竹云IDaaS应用的 ClientId
替换JavaScript代码中的redirect_uri为您的demo示例的callback.html地址。
替换JavaScript代码中的url中yourdomain为您的域名,即竹云IDaaS域名。
<!DOCTYPE html>
<html>
<head>
<title>IDaaS Cognito OIDC 示例</title>
</head>
<body>
<h2>IDaaS and Amazon Cognito OpenID 集成示例</h2>
<p>
本demo演示IDaaS如何与Amazon Cognito通过OIDC集成的web应用程序示例,该示例允许用户使用其IDaaS用户名和密码登录并获得Cognito令牌。
</p>
<p>本demo完全使用JavaScript编写,仅包含两个文件 - <b>index.html</b> 和 <b>callback.html</b>.</p>
<p>首先,请点击 <b><button onclick="login()">使用IDaaS登录Demo</button></b>。如果认证成功,我们将会跳转 <b>callback.html</b>,并成功展示Cognito令牌。</p>
</body>
<script type="text/javascript">
function login() {
// 替换IDaaS应用的 ClientId
var client_id = 'yeMSd6WRMnNoVXXXXXXncXLV9l2jXZ';
// 替换callback.html地址
var redirect_uri = 'https://localhost/callback';
// 替换url中yourdomain为您的域名,即IDaaS域名
var url = 'https://{yourdomain}/api/v1/oauth2/authorize'
+ '?response_type=token id_token'
+ '&scope=openid'
+ '&nonce=abc'
+ '&client_id=' + client_id
+ '&redirect_uri=' + redirect_uri;
window.location.replace(url);
}
</script>
</html>callback.html
callback.html是用户登录后竹云IDaaS将其重定向到demo示例时看到的页面。
下面列出callback.html的完整标记和代码,您还需要以下三步:
替换JavaScript代码中的aws_region为您的Cognito用户池地区。
替换JavaScript代码中的provider_url中yourdomain为您的域名,即您在【AWS IAM 配置】获取的提供商名称。
替换JavaScript代码中的pool_id为您的身份池ID,即您在【AWS Cognito 配置】获取的身份池ID
<!DOCTYPE html>
<html>
<head>
<title>IDaaS Cognito OIDC 示例</title>
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.850.0.min.js"></script>
</head>
<body onload="callback()">
<h2>IDaaS 和 Amazon Cognito OpenID 集成示例</h2>
<h4></h4>
<h4></h4>
<h4></h4>
<h4></h4>
<h4></h4>
<h4></h4>
</body>
<script type="text/javascript">
function callback() {
var url = window.location.href;
var error = url.match('error=([^&]*)')
if (error) {
var description = url.match('error_description=([^&]*)')
printMessage('Error', 'Error: ' + error[1] + '
Description: ' + description[1] + '</br>');
return;
}
var match = url.match('id_token=([^&]*)');
if (match) {
var id_token = match[1];
if (id_token) {
printMessage('Error', '使用IDaaS的ID Token获取Cognito令牌');
makeCognitoRequest(id_token);
}else{
printMessage('Error', 'Error: 无法从URL中检索id token');
}
}else{
printMessage('Error', 'Error: URL中没有id token');
}
}
async function makeCognitoRequest(id_token) {
// 替换aws_region为您的Cognito用户池地区
var aws_region = 'cn-north-1';
// 替换provider_url中yourdomain为您的域名
var provider_url = '{yourdomain}/api/v1/oauth2';
// 替换pool_id为您的身份池ID
var pool_id = 'cn-north-1:469392b9-XXXX-XXXX-9877-7d34c3ca2a47';
var logins = {};
logins[provider_url] = id_token;
AWS.config.region = aws_region;
try {
const cognitoIdentity = new AWS.CognitoIdentity();
const { IdentityId } = await cognitoIdentity.getId({
IdentityPoolId: pool_id,
Logins: logins
}).promise()
const { Credentials } = await cognitoIdentity.getCredentialsForIdentity({
IdentityId: IdentityId,
Logins: logins
}).promise()
printMessage('IdentityId', 'IdentityId: ' + IdentityId);
printMessage('AccessKeyId','AccessKeyId: ' + Credentials.AccessKeyId);
printMessage('SecretKey','SecretKey: ' + Credentials.SecretKey);
printMessage('SessionToken','SessionToken: ' + Credentials.SessionToken);
printMessage('Expiration','Expiration: ' + Credentials.Expiration);
} catch (e) {
printMessage('Error', e);
}
}
function printMessage(elementId, messageString){
document.getElementById(elementId).innerHTML = messageString;
}
</script>
</html>登录验证
现在一切就绪,可以测试示例demo示例。
在index.html页面中,点击使用竹云IDaaS登录Demo。

使用您的竹云IDaaS用户名和密码登录。
登录成功后将重定向到callback.html页面。您将看到以下AWS临时凭证。

使用AWS临时凭证,访问AWS服务,如API 网关,S3, IoT, AI 等服务。