【问题标题】:Control access for invoking Rest API in API Gateway在 API Gateway 中控制调用 Rest API 的访问权限
【发布时间】:2020-05-11 12:46:25
【问题描述】:

我有几个 API 网关资源,我想允许其他服务调用它们。 假设我有这两个端点:

  • /任务
  • /设置

我的客户是一些服务,他们像以下请求一样调用这些 Rest API:(它是用 Javascript 编写的,但他们可以使用任何其他编程语言,但不能使用 AWS SDK)

fetch('.../tasks')
.then((tasks) => {
console.log('Tasks:', tasks)
});

我需要在客户调用我的 API 时检查他们的权限。当一个服务向 /tasks 发送请求时,我应该检查它的权限,看看它是否没有所需的权限,我会返回 403 作为响应。

我想知道实现它的最佳方法是什么?我应该使用与身份池集成的 AWS Cognito 用户池还是自定义授权方?

如果我的问题不够清楚,请发表评论,我会提供更多信息。

希望有人有相关经验,可以帮助我。

【问题讨论】:

    标签: amazon-web-services authentication authorization amazon-cognito lambda-authorizer


    【解决方案1】:

    API 用户在 API 请求中包含 IAM 用户的访问密钥。 Details.

    您需要选择适合您业务需求的身份提供者。

    【讨论】:

      【解决方案2】:

      分享我的发现已经很晚了,但我会为其他在 AWS 身份验证和授权方面遇到相同问题的人写下方法。

      首先,请注意以下要求无法通过 AWS Cognito 实现。换句话说,我们必须使用 AWS SDK(据我了解)来获得 AWS 凭证。

      我的客户是一些服务,他们像以下请求一样调用这些 Rest API:(它是用 Javascript 编写的,但他们可以使用任何其他编程语言,但不能使用 AWS SDK)

      让我们看看 AWS Cognito 及其组件的描述,基于 AWS 文档:

      Amazon Cognito 提供身份验证、授权和用户 管理您的网络和移动应用程序。您的用户可以登录 直接使用用户名和密码,或通过第三方等 如 Facebook、亚马逊、谷歌或苹果。

      Amazon Cognito 的两个主要组件是用户池和身份 池。用户池是提供注册和 应用程序用户的登录选项。身份池使您能够授予 您的用户可以访问其他 AWS 服务。

      所以为了澄清上面的解释,我们可以使用用户池组件来提供身份验证和身份池,以提供对 AWS 服务的访问和最终授权。

      您应该注意的是,如果不使用身份池,AWS 不支持授权。

      由于有一篇关于如何实现身份验证和授权的信息丰富的文章 - 链接如下 - 我只是简要介绍了相关场景,我发现在完成实施步骤之前了解这些内容很有用。

      http://interworks.com.mk/amazon-cognito-and-api-gateway-aws-iam-authorization/

      1. 用户应使用用户池对自己进行身份验证。您的应用用户可以直接通过用户池登录,也可以通过第三方身份提供商 (IdP) 联合登录。登录过程可以通过 Web 或 API 进行。

      2. 身份验证成功后,您的 Web 或移动应用程序将从 Amazon Cognito 接收经过身份验证的用户的用户池令牌。

      3. 您应该使用这些令牌来检索允许您的应用访问其他 AWS 服务的 AWS 凭证。

      4. 您可以使用收到的凭证发送访问 AWS 服务的请求,在我们的示例中为 API Gateway。向 AWS API Gateway 发送请求有两种选择。第一个使用 AWS SDK,第二个使用其他库,例如 Axios。关键是如果您手动发送请求(例如通过 axios),您应该在发送之前签署请求。但如果您使用 AWS SDK,AWS SDK 将自行处理签名过程,您无需执行任何操作。

      有一个示例代码在 NodeJs 中实现了这个场景。在这个示例中,我们使用 Axios 库将请求发送到 API Gateway。

      const AWS = require("aws-sdk");
      const crypto = require("crypto");
      const aws4 = require("aws4");
      const axios = require("axios");
      
      // Client information
      const CLIENT_SECRET = "######";
      const CLIENT_ID = "####";
      const USER_POOL_ID = "####";
      const IDENTITY_POOL_ID = "####";
      const COGNITO_AUTH_PROVIDER =
        "cognito-idp.<REGION>.amazonaws.com/<USER_POOL_ID>";
      
      // AWS config
      AWS.config.region = "XXXX";
      
      // If client_secret is enabled in user pool, client_secret should be converted to a Base64 encoded value called HASH_SECRET
      const createHashSecret = (username) => {
        return crypto
          .createHmac("SHA256", CLIENT_SECRET)
          .update(`${username}${CLIENT_ID}`)
          .digest("base64");
      };
      
      // User information
      const userInfo = {
        username: "###",
        password: "###",
      };
      
      const userPoolData = {
        UserPoolId: USER_POOL_ID,
        ClientId: CLIENT_ID,
      };
      
      /**
       * Add user credential to AWS request sent by HTTP
       * By Signature Version 4
       */
      const generateApiGatewayRequest = (credentials, requestParams) => {
        const { url, hostname, path, method } = requestParams;
        const options = {
          service: "execute-api",
          region: AWS.config.region,
          url,
          hostname,
          path,
          method,
          headers: {
            "Content-Type": "application/json",
            Accept: "application/json",
          },
        };
      
        // Sign the request by some metadata
        return aws4.sign(options, credentials);
      };
      
      // Create an authentication client to connect to user pool
      const cognitoIdentityServiceProvider = new AWS.CognitoIdentityServiceProvider(
        userPoolData
      );
      
      // Request to authenticate a user
      cognitoIdentityServiceProvider.initiateAuth({
        AuthFlow: "USER_PASSWORD_AUTH",
        ClientId: CLIENT_ID,
        AuthParameters: {
          USERNAME: userInfo.username,
          PASSWORD: userInfo.password,
          SECRET_HASH: createHashSecret(userInfo.username),
        },
      }, function (err, data) {
        if (err) {
          // Something wrong has happened, like invalid user info, invalid pool and client info, ...
          // The error object contains message, code, time, requestId, statusCode, ...
          console.log(err);
        } else {
          // id token, access token and refresh token have been created.
          console.log(data.AuthenticationResult);
      
          // Request for authorization with Identity pool
          AWS.config.credentials = new AWS.CognitoIdentityCredentials({
            IdentityPoolId: IDENTITY_POOL_ID,
            Logins: {
              [COGNITO_AUTH_PROVIDER]: data.AuthenticationResult.IdToken,
            },
          });
      
          // Check if the request for AWS credential has been done successfully
          AWS.config.credentials.get(function (err) {
            if (err) {
              // There is no received credential
              console.log(err);
            } else {
              // The logged-in user now has a temporary credential to ask for AWS services such as Api Gateway
              // The credential includes accessKeyId, secretAccessKey, sessionToken, etc
              var userCredential = AWS.config.credentials;
      
              // Request protected resources (Api Gateway)
              axios(
                generateApiGatewayRequest(userCredential, {
                  url:
                    "https://XXX.execute-api.us-east-1.amazonaws.com/main/tasks",
                  hostname: "XXX.execute-api.us-east-1.amazonaws.com",
                  path: "/main/tasks",
                  method: "GET",
                })
              )
                .then((result) => {
                  // Request's been done successfully
                  console.log(result);
                })
                .catch((error) => {
                  // The error could be either resource errors like Bad Request or Forbidden as the user doesn't have the permission to access the resource
                  console.log(error);
                });
            }
          });
        }
      });
      

      有关详细信息,请参阅上面链接的文章。但是,如果仍有一些模棱两可的部分,请随时在下面发表评论。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2015-04-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-26
        • 2015-03-04
        • 1970-01-01
        • 2015-11-12
        相关资源
        最近更新 更多