AWS国内版Cognito身份池

单点登录SSO

# 说明

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或平台。

# 身份验证流程

流程说明

  1. 用户访问示例demo示例并单击“使用IDaaS登录”按钮。

  2. 该demo示例将用户重定向到IDaaS进行登录。成功验证后,该demo示例会从IDaaS接收ID Token。

  3. 该demo示例将ID Token交换成Cognito令牌。

  4. 该demo示例将Cognito令牌交换成临时AWS安全凭据。

  5. 该demo示例使用凭据访问AWS服务。

# 前提条件

# IDaaS配置

  1. 登录IDaaS企业中心【资源】->【应用】->【添加自建应用】,应用名称可以写【Cognito OIDC示例】,认证集成选择【OIDC】。

  2. 配置应用认证参数。

  • 回调地址:请指定Web服务器上Callback.html文件的路径。示例:https://localhost/callback.html
  • 隐式授权模式:本demo示例需要将隐式授权模式开启,如果您的应用程序是后端和IDaaS集成,您也可以选择关闭隐式授权模式,使用授权码模式,通过授权码来获取 ID Token,以便 Demo 中使用 IDaaS 的 ID Token 交换 Cognito 令牌。

请记住IDaaS应用的 ClientId , 我们将提供给 AWS 作为 OpenId Connect 身份提供商的“受众”。

  1. 应用左侧菜单栏下切换至 【授权管理】->【应用账号】” 页签,添加账号。

# AWS IAM 配置

  1. 登录 AWS Console。

  2. 在“All services”选择“身份和访问管理(IAM)”。

  3. 选择“身份提供商”。

  4. 点击“添加提供商”,选择“OpenID Connect”。

  5. 填写“提供商 URL”:示例:https://{yourdomain}/api/v1/oauth2, 更换示例中yourdoamin为您的IDaaS域名,点击【获取指纹】。

  6. 填写“受众”:您的IDaaS应用的 ClientId,即您在上一步IDaaS平台建的应用,保存成功。

请记您的提供商名称,因为我们稍后在创建示例demo示例时需要它,示例:{yourdomain}/api/v1/oauth2

# AWS Cognito 配置

  1. 登录 AWS Console。

  2. 在“All services”选择“Cognito”。

  3. 选择您的身份池, 如果没有身份池,请“创建身份池”。

  4. 配置身份池信任,选择身份来源:OpenID Connect (OIDC),点击“下一步”。

  5. 创建IAM角色名称,示例:Cognito_IDaaSAuth_Role。可以查看策略详情,Cognito自动增加GetCredentialsForIdentity权限

    {
        "Effect": "Allow",
        "Action": [
            "cognito-identity:GetCredentialsForIdentity"
        ],
        "Resource": [
            "*"
        ]
    }
1
2
3
4
5
6
7
8
9
  1. 选择您前面建的身份提供商,点击保存。

请记住身份池ID,因为我们稍后在创建示例demo示例时需要它。

# 创建示例程序

  • demo示例只包含两个文件 — index.htmlcallback.html。在本节中,我将显示这两个文件的完整代码列表。接下来,您只需要分别更新文件中三个变量,然后将它们部署到您的服务器中。

# index.html

index.html文件显示“使用IDaaS登录”按钮,并将用户重定向到IDaaS进行身份验证。此文件是示例demo示例的起点。它需要配置您的应用的 ClientId,这就是IDaaS知道登录请求来自哪个demo示例的方式。

下面列出index.html的完整标记和代码,您还需要以下三步:

  1. 替换JavaScript代码中的client_id为您的 ClientId,即您在【IDaaS配置】获取的IDaaS应用的 ClientId

  2. 替换JavaScript代码中的redirect_uri为您的demo示例的callback.html地址。

  3. 替换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.html';
    
    // 替换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>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

# callback.html

callback.html是用户登录后IDaaS将其重定向到demo示例时看到的页面。

下面列出callback.html的完整标记和代码,您还需要以下三步:

  1. 替换JavaScript代码中的aws_region为您的Cognito用户池地区。

  2. 替换JavaScript代码中的provider_url中yourdomain为您的域名,即您在【AWS IAM 配置】获取的提供商名称。

  3. 替换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><span id="Error" style="color:#FF0000"></span></h4>
	<h4><span id="IdentityId" style="color:#2196f3"></span></h4>
	<h4><span id="AccessKeyId" style="color:#2196f3"></span></h4>
	<h4><span id="SecretKey" style="color:#2196f3"></span></h4>
	<h4><span id="SessionToken" style="color:#2196f3;word-break:break-all"></span></h4>
	<h4><span id="Expiration" style="color:#2196f3"></span></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] + '<br>Description: ' + description[1] + '</br>');
            return;
        }
        var match = url.match('id_token=([^&]*)');
        if (match) {
            var id_token = match[1]; 
            if (id_token) {
                printMessage('Error', '<span style="color:#000000">使用IDaaS的ID Token获取Cognito令牌</span>');
                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', '<span style="color:#000000">IdentityId: </span>'  + IdentityId);  
            printMessage('AccessKeyId','<span style="color:#000000">AccessKeyId: </span>'  + Credentials.AccessKeyId);   
            printMessage('SecretKey','<span style="color:#000000">SecretKey: </span>'  + Credentials.SecretKey);   
            printMessage('SessionToken','<span style="color:#000000">SessionToken: </span>'  + Credentials.SessionToken); 
            printMessage('Expiration','<span style="color:#000000">Expiration: </span>'  + Credentials.Expiration);       
        } catch (e) {
            printMessage('Error', e);  
        }     
    } 
    function printMessage(elementId, messageString){
       document.getElementById(elementId).innerHTML = messageString;
    }    
</script>
</html>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72

# 登录验证

现在一切就绪,可以测试示例demo示例。

  1. 在index.html页面中,单击使用IDaaS登录Demo。

  2. 使用您的IDaaS用户名和密码登录。

  3. 登录成功后将重定向到callback.html页面。您将看到以下AWS临时凭证。

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