65.9K
CodeProject 正在变化。 阅读更多。
Home

从 JavaScript 调用 API Gateway/Cognito

starIconstarIconstarIconstarIconstarIcon

5.00/5 (1投票)

2019 年 12 月 30 日

CPOL

2分钟阅读

viewsIcon

8310

了解如何从 JavaScript 客户端应用程序调用带 Cognito 凭据的 API Gateway。

引言

在本文中,我们将介绍一个简单的 JavaScript 应用程序,它可以利用 Cognito 登录的凭据向 AWS API Gateway 实例发出经过身份验证的 HTTP 请求。

背景

此示例项目的源代码可以在 GitHub 上找到。

此视频在 YouTube 上,展示了如何使用 API Gateway、Cognito、Lambda 和 S3 将此代码部署到 AWS 的屏幕录制。

Using the Code

我们首先从 AWS Amplify 库中导入 AmplifyAuth

import Amplify, {Auth} from 'aws-amplify';

Amplify 类需要配置 AWS 区域、Cognito 用户池 ID 和 Cognito 应用程序客户端 ID。 我们从 URL 查询参数获取这些信息,以使示例具有通用性。

/*
    Configure the Amplify library with the details required to access a Cognito user pool
 */
var urlParams = new URLSearchParams(window.location.search);
Amplify.configure({
    Auth: {
        // Amazon Cognito Region
        region: 'us-east-1',

        // Amazon Cognito User Pool ID
        userPoolId: urlParams.get('poolId'),

        // Amazon Cognito Web Client ID (26-char alphanumeric string)
        userPoolWebClientId: urlParams.get('appId'),
    }
});

我们在这里执行初始登录。 用户名和密码通过 Auth.signin() 方法发送到 Cognito,响应将是成功,或请求其他信息。

我们仅捕获密码更改的请求,因为 Cognito 服务强制通过 AWS Web 控制台创建的每个用户都进入一种必须更改初始密码的状态。 但您可能需要响应许多其他情况,包括电话号码、电子邮件地址、双因素身份验证令牌等的请求。

登录或密码更改成功后,我们调用 displayTokens() 函数。

/**
 * Attempt the initial login of a Cognito user. This may result in a password change
 * form being displayed if required. Once logged in, the id and access tokens will
 * be displayed.
 * @param username The Cognito username
 * @param password The Cognito password
 */
async function signIn(username, password) {
    const user = await Auth.signIn(username, password);
    if (user.challengeName === 'NEW_PASSWORD_REQUIRED') {

        initiallogin.style.display = "none";
        changepassword.style.display = "";

        changepass.onclick = async () => {
            await Auth.completeNewPassword(
                user,
                newpassword.value
            ).then((user) => {
                displayTokens(user);
            });
        };
    } else {
        displayTokens(user);
    }
}

displayTokens() 函数中,我们获取用户会话,从中可以获取 ID 和访问令牌。 这些令牌在调用 API Gateway 端点时发送在 Authorization 标头中(通过 invokeURL 查询参数传入)。

重要的是要注意,即使 HTTP 规范规定您必须这样做,我们也不会在标头值中添加 bearer 前缀。 这是 API Gateway Cognito 授权器中的一个已知错误,即不支持此前缀。

/**
 * Display the id and access tokens from the logged in Cognito user
 * @param user The CognitoUser returned as a result of a successful login
 */
function displayTokens(user) {
    initiallogin.style.display = "none";
    changepassword.style.display = "none";
    results.style.display = "";

    user.getSession((err, session) => {
        accessToken.value = session.accessToken.jwtToken;
        idToken.value = session.idToken.jwtToken;

        fetch(urlParams.get('invokeURL') + "/test", 
             {headers: {'Authorization': session.idToken.jwtToken}})
            .then(response => response.text())
            .then(text => apiCall.value = text);
    });
}

最后一步是将事件挂接到初始登录按钮单击。

/*
    Attach an event handler to the login click event
 */
login.onclick = () => signIn(username.value, password.value);

这是显示登录表单的 HTML 页面

<html>
<head>

</head>
<body>
<div id="initiallogin">
    <label>Username</label>
    <input id="username"
           type="text"/>
    <label>Password</label>
    <input id="password"
           type="text"/>
    <input id="login"
           type="button"
           value="Login"/>
</div>
<div id="changepassword"
     style="display: none">
    <label>New Password</label>
    <input id="newpassword"
           type="text"/>
    <input id="changepass"
           type="button"
           value="Change Password"/>
</div>
<div id="results"
     style="display: none">
    <h3>ID Token</h3>
    <textarea cols="100"
              id="idToken"
              readonly="true"
              rows="15"></textarea>
    <h3>Access Token</h3>
    <textarea cols="100"
              id="accessToken"
              readonly="true"
              rows="15"></textarea>
    <h3>API Call Result</h3>
    <textarea cols="100"
              id="apiCall"
              readonly="true"
              rows="15"></textarea>
</div>
<script src="main.js"></script>
</body>
</html>

历史

  • 2019 年 12 月 30 日 - 初始发布
© . All rights reserved.