Reactjs 中的 AWS Cognito 身份验证

AWS Cognito Authentication in Reactjs

我已经使用 Firebase 和 React 构建了应用程序,过程非常顺畅。

最近我被要求使用 AWS Cognito,由于文档不清楚,设置起来似乎有点痛苦。

首先,如何使用 Cognito 进行用户身份验证?我使用以下应用程序客户端设置设置了一个用户池:

现在,我将授权人添加到我的 API 中,如下所示:

现在我的问题是,如何在我的前端使用它来登录用户并进行经过身份验证的 API 调用?

似乎有两种不同的工具包可用:

  1. https://github.com/aws/aws-sdk-js
  2. https://github.com/aws-amplify/amplify-js

初学者根本不清楚要使用什么,以及如何进行身份验证。理想情况下,我会像使用 firebase 一样使用它,让我的前端使用电子邮件和密码进行身份验证调用,然后接收某种令牌(仅在成功时),然后可以使用该令牌进行签名 API 来电。

有人可以帮忙提供代码示例吗?

抱歉造成混淆。

AWS Cognito 用户池充当身份提供商。它支持所有用户管理(注册、登录、密码重置、用户删除等)。 Cognito 还支持 Federated Identity(例如,已经拥有 Google/Facebook 帐户的用户可以登录)。在这种情况下,Cognito 使用 OAuth 与 Google/Facebook 对话。

当我学习 Cognito/JWT 令牌时,我创建了一个简单的 JS/HTML 来了解它是如何工作的。由于您要求提供代码,因此您可以参考它 - https://github.com/ryandam9/Cognito-tokens.

根据您的屏幕截图,您已经配置了一个用户池 - sls-notes-backend。比如说,您将强制属性配置为 Email.

步骤 0 - 初始化 创建用户池时,您会同时获得 userPoolIdappId

poolData = {
    UserPoolId: userPoolId,
    ClientId: appId
};

userPool = new AWSCognito.CognitoIdentityServiceProvider.CognitoUserPool(poolData);

第 1 步 - 使用电子邮件和密码注册用户 - 假设您的 UI 已经从用户那里捕获了这些详细信息并且用户点击了 'Sign Up' 按钮.

/**
 * Signup a User
 * @param e
 */
function addUser(e) {
    signupMessage.style.display = 'none';
    signupMessage.className = '';

    e.preventDefault();

    let name = document.getElementById('name').value.trim();
    let email = document.getElementById('signup-email').value.trim();
    let password = document.getElementById('signup-password').value.trim();

    if (name.length === 0 || email === 0 || password === 0) {
        return;
    }

    let attributeList = [
        new AWSCognito.CognitoIdentityServiceProvider.CognitoUserAttribute({
            Name: 'given_name', Value: name
        }),
    ];

    userPool.signUp(email, password, attributeList, null, function (err, result) {
        if (err) {
            signupMessage.innerText = err;
            signupMessage.style.display = 'block';
            signupMessage.className = 'alert alert-danger';
            return;
        }

        cognitoUser = result.user;
        console.log('user name is ' + cognitoUser.getUsername());

        // Show a text box to enter Confirmation code
        document.getElementById('signup-btn').style.display = 'none';
        document.getElementById('code-block').style.display = 'block';
        document.getElementById('confirm-user-btn').style.display = 'inline-block';
    });
}

如果注册成功(是有效的Email,并且该Email在Userpools中还不存在,会向提供的Email发送确认码。下一步是,让用户输入密码并确认他的身份。

步骤 3 - 确认用户

/**
 * Confirm the user by taking the Confirmation code.
 * @param e
 */
function confirmUser(e) {
    e.preventDefault();
    let verificationCode = document.getElementById('code').value;

    cognitoUser.confirmRegistration(verificationCode, true, function (err, result) {
        if (err) {
            signupMessage.innerText = err;
            signupMessage.style.display = 'block';
            signupMessage.className = 'alert alert-danger';
            return;
        }

        signupMessage.innerText = result;
        signupMessage.style.display = 'block';
        signupMessage.className = 'alert alert-success';
    });
}

如果用户输入正确的代码,则他的身份得到确认。此时,为该用户在用户池中创建了一个条目。看起来像这样

步骤 4 - 身份验证(登录) 至此,用户注册完成。是时候让他登录了。请忽略下面代码中不必要的代码(获取和打印凭据的代​​码,解码部分)。 如果身份验证成功,Cognito returns 应用程序的两种令牌 - ID 令牌和访问令牌。这些仅适用于此 session 且仅适用于此用户。 此处有更多详细信息 - https://ryandam.net/aws/19-cognito-userpools/index.html#0

/**
 * Signin user with Email and Password
 * @param e
 */
function authenticateUser(e) {
    e.preventDefault();

    let email = document.getElementById('signin-email').value;
    let password = document.getElementById('signin-password').value;

    if (email.length === 0 || password === 0 || userPool === null || userPool === undefined) {
        signinMessage.innerText = 'Fill in all fields!';
        signinMessage.style.display = 'block';
        signinMessage.className = 'alert alert-danger';
        return;
    }

    let authenticationData = {
        Username: email,
        Password: password,
    };

    let authenticationDetails = new AWSCognito.CognitoIdentityServiceProvider.AuthenticationDetails(authenticationData);

    let userData = {
        Username: email,
        Pool: userPool
    };

    let cognitoUser = new AWSCognito.CognitoIdentityServiceProvider.CognitoUser(userData);

    cognitoUser.authenticateUser(authenticationDetails, {
            onSuccess: function (result) {
                signinMessage.innerText = 'Authentication Success!';
                signinMessage.style.display = 'block';
                signinMessage.className = 'alert alert-success';

                document.getElementById('token-section').style.display = 'block';
                document.getElementById('signin-btn').style.display = 'none';

                // Decode ID Token
                let idToken = result.idToken.jwtToken;
                document.getElementById('id-token').innerText = idToken;
                document.getElementById('decoded-id-token').appendChild(parseIdToken(idToken));

                // Decode Access Token
                let accessToken = result.getAccessToken().getJwtToken();
                document.getElementById('access-token').innerText = accessToken;
                document.getElementById('decoded-access-token').appendChild(parseAccessToken(accessToken));

                let cognitoUser = userPool.getCurrentUser();

                if (cognitoUser != null) {
                    cognitoUser.getSession(function (err, result) {
                        if (result) {
                            // Set the region where your identity pool exists (us-east-1, eu-west-1)
                            AWS.config.region = region;
                            AWS.config.update({region: region});

                            logins = {};
                            let key = 'cognito-idp.us-east-2.amazonaws.com/' + userPoolId;
                            logins[key] = result.getIdToken().getJwtToken();

                            // Add the User's Id Token to the Cognito credentials login map.
                            AWS.config.credentials = new AWS.CognitoIdentityCredentials({
                                IdentityPoolId: identityPoolId,
                                Logins: logins,
                            });

                            // Make the call to obtain credentials
                            AWS.config.credentials.get(function () {
                                // Credentials will be available when this function is called.
                                var accessKeyId = AWS.config.credentials.accessKeyId;
                                var secretAccessKey = AWS.config.credentials.secretAccessKey;
                                var sessionToken = AWS.config.credentials.sessionToken;
                            });

                            if (s3BucketName.length > 0)
                                listS3Bucket(s3BucketName);
                        }
                    });
                }
            },
            onFailure: function (err) {
                signinMessage.innerText = err;
                signinMessage.style.display = 'block';
                signinMessage.className = 'alert alert-danger';
            }
        }
    );
}

第 5 步 - 调用您已经创建的 API 端点 - 因为您已经使用Userpool 并且您正在使用 Authorization 作为 header,您可以通过将 ID 令牌作为授权 header 传递来从 JS 调用端点。发生的事情是,令牌由授权方验证。由于它是有效的,用户可以调用 API.**

我没有 JS 代码,你可以从 CLI/Postman 测试你的 API,像这样:

备注 AWS Amplify 似乎是 Cognito 和其他服务的包装器。例如,当您调用其 CLI 命令时,Amplify 会为您设置用户池。如果您想了解 Amplify 如何与 Flutter 配合使用,可以参考此代码 - https://github.com/ryandam9/Auth-flutter-aws-amplify.

我还在学习。我尽量做到准确。