首页  »  AWS 教程

使用 Amazon Neptune 构建游戏好友推荐引擎

向应用程序中添加身份验证

在本模块中,您将配置 Amazon Cognito,以便在应用程序中用作身份验证提供程序。Amazon Cognito 是一个全托管的身份验证提供程序,支持用户注册、验证、登录等功能。

Amazon Cognito 包含两个不同的组件:User Pools(用户池)和 Identity Pools(身份池)。用户池是标准的用户目录,用户可以通过 Amazon Cognito 或第三方身份(如 Facebook)登录。身份验证成功后,用户会收到相应令牌(例如访问令牌或身份令牌),可用于访问后端资源。

相比之下,通过身份池,用户可以获得临时的 AWS 凭证来访问 AWS 资源。身份池可以用来提供对 AWS Lambda 函数、Amazon DynamoDB 表或其他资源的有限的直接访问。

本教程将使用 Amazon Cognito 用户池。我们允许用户通过我们的应用程序注册。注册后,用户可以通过客户端登录并获取身份令牌。该身份令牌可以作为请求标头传递给应用程序,用于用户身份验证。

在接下来的步骤中,您将创建一个 Amazon Cognito 用户池。然后创建一个客户端应用程序来访问该用户池。最后,我们来看一些与用户池交互的示例代码。

 完成时间

10 分钟


  • 用户池是一个用户目录,用户和用户组的所有管理操作都在该池中进行。创建用户池时,您需要为其指定规则,包括密码策略和必填属性。

     scripts/ 目录中,有一个名为 create-user-pool.sh 的文件。该文件内容如下所示:

    USER_POOL_ID=$(aws cognito-idp create-user-pool \
      --pool-name recommendation-users \
      --policies '
          {
          "PasswordPolicy": {
            "MinimumLength": 8,
            "RequireUppercase": true,
            "RequireLowercase": true,
            "RequireNumbers": true,
            "RequireSymbols": false
          }
        }' \
      --query 'UserPool.Id' \
      --output text)
    
    echo "User Pool created with id ${USER_POOL_ID}"
    
    echo "export USER_POOL_ID=${USER_POOL_ID}" >> env.sh

    该脚本使用 AWS 命令行界面 (AWS CLI) 创建用户池。其中将用户池 (USER_POOL) 命名为 recommendation-users,同时定义了密码策略。脚本要求密码长度至少为 8 个字符,且必须包含大写字母、小写字母和数字。

    您可以运行以下命令来执行该脚本,创建用户池:

    bash scripts/create-user-pool.sh

    您应当会看到以下输出结果:

    User Pool created with id <user-pool-id>

    下一步,我们将创建一个客户端来访问该用户池。

  • 用户池配置完成后,接下来需要创建一个 User Pool Client(用户池客户端)。用户池客户端用于调用用户池的非身份验证方法,例如用户注册和登录。

    我们后端的 Node.js 应用程序将使用该用户池客户端。要注册或登录,用户向应用程序发送包含相关属性的 HTTP POST 请求。应用程序使用用户池客户端,将这些属性转发至 Amazon Cognito 用户池。然后,应用程序返回相应的数据或错误消息。

    在 scripts/ 目录中,有一个名为 create-user-pool-client.sh 的文件,用于创建用户池客户端。此文件的内容如下所示:

    source env.sh
    
    CLIENT_ID=$(aws cognito-idp create-user-pool-client \
      --user-pool-id ${USER_POOL_ID} \
      --client-name recommendation-backend \
      --no-generate-secret \
      --explicit-auth-flows ADMIN_NO_SRP_AUTH \
      --query 'UserPoolClient.ClientId' \
      --output text)
    
    echo "User Pool Client created with id ${CLIENT_ID}"
    
    echo "export COGNITO_CLIENT_ID=${CLIENT_ID}" >> env.sh

    该脚本将为新创建的用户池创建一个用户池客户端。其中的 ADMIN_NO_SRP_AUTH 是一种可用于服务器端应用程序的身份验证流程。由于我们使用的是服务器端流程,所以不需要客户端流(例如移动设备或单页应用程序)中使用的 Client Secret(客户端密钥)。

    运行该脚本,使用以下命令创建用户池客户端:

    bash scripts/create-user-pool-client.sh

    您应当会看到以下输出结果:

    User Pool Client created with id <client-id>

    在本模块的最后一步,我们来学习一下应用程序中用到的身份验证相关代码。

  • 现在用户池和访问该池的客户端都已创建完毕。让我们来看看如何在应用程序中使用 Amazon Cognito。

    在项目的 application/ 目录中,有一个名为 auth.js 的文件。该文件包含一些用于应用程序身份验证的辅助函数。文件中有三个核心函数。下面我们来逐一介绍。

    第一个函数是 createCognitoUser,用于在 Amazon Cognito 中注册新用户。此函数如下所示:

    const createCognitoUser = async (username, password, email) => {
      const signUpParams = {
        ClientId: process.env.COGNITO_CLIENT_ID,
        Username: username,
        Password: password,
        UserAttributes: [
          {
            Name: 'email',
            Value: email
          }
        ]
      }
      await cognitoidentityserviceprovider.signUp(signUpParams).promise()
      const confirmParams = {
        UserPoolId: process.env.USER_POOL_ID,
        Username: username
      }
      await cognitoidentityserviceprovider.adminConfirmSignUp(confirmParams).promise()
      return {
        username,
        email
      }
    }

    该函数使用上一步设置的 Amazon Cognito 客户端 ID,以及用户提供的用户名、密码和电子邮件来创建新用户。另外,函数还将立即对用户进行确认,以便其可以直接登录。通常情况下,应用程序应包含一个验证流程来校验用户的邮箱和/或手机号码,以获取用户的联系方式。不过此内容不在本教程讨论范围之内,您只需自动确认新用户即可。

    第二个核心方法是 login 函数,在已注册用户登录时用于身份验证。代码如下所示:

    const login = async (username, password) => {
      const params = {
        ClientId: process.env.COGNITO_CLIENT_ID,
        UserPoolId: process.env.USER_POOL_ID,
        AuthFlow: 'ADMIN_NO_SRP_AUTH',
        AuthParameters: {
          USERNAME: username,
          PASSWORD: password
        }
      }
      const { AuthenticationResult: { IdToken: idToken } }= await cognitoidentityserviceprovider.adminInitiateAuth(params).promise()
      return idToken
    }

    和 createCognitoUser 函数类似,我们使用客户端 ID 和提供的参数调用 Amazon Cognito。Amazon Cognito 的 adminInitiateAuth 方法用于用户身份验证,如果验证通过,就返回令牌。我们使用 IdToken(身份令牌)进行身份验证,所以用户登录成功时返回的就是身份令牌。

    最后是 verifyToken 函数。此函数的内容如下所示:

    const verifyToken = async (idToken) => {
      function getKey(header, callback){
        client.getSigningKey(header.kid, function(err, key) {
          var signingKey = key.publicKey || key.rsaPublicKey;
          callback(null, signingKey);
        });
      }
    
      return new Promise((res, rej) => {
        jwt.verify(idToken, getKey, {}, function(err, decoded) {
          if (err) { rej(err) }
          res(decoded)
        })
      })
    }

    该函数验证请求中传入的身份令牌。Amazon Cognito 提供的身份令牌是 JSON Web 令牌 (JWT)。verifyToken 函数确认令牌是由受信任的源签发的,并验证用户身份。在需要身份验证的 Endpoint(端点)中使用此函数,确保发出请求的用户有访问权限。

    在接下来的模块中,我们会在后端应用程序中用到这三个身份验证函数。


总结

在本模块中,我们创建并配置了 Amazon Cognito 用户池及其客户端。我们还了解了一些辅助函数,用于与 Amazon Cognito 用户池交互,实现用户注册、登录和验证。

在下一个模块中,我们将使用 AWS Lambda 和 Amazon API Gateway 等无服务器技术来部署后端应用程序。