0

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

  • /任务
  • /环境

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

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

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

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

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

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

4

2 回答 2

0

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

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

于 2020-01-27T07:37:00.150 回答
0

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

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

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

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

Amazon Cognito 为您的 Web 和移动应用程序提供身份验证、授权和用户管理。您的用户可以使用用户名和密码直接登录,也可以通过 Facebook、Amazon、Google 或 Apple 等第三方登录。

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);
          });
      }
    });
  }
});

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

于 2020-08-16T13:42:37.797 回答