使用 Cognito 对 AWS Api Gateway 中的用户进行身份验证

问题描述 投票:0回答:2

我想使用 Aws Rest Api Gateway 构建一个 Rest API。这将是现有生产 api(托管在私有服务器上)的新版本。

在当前版本的 api 中,我们使用带有授予类型密码的 oauth2 进行身份验证。这意味着客户端发送其用户名并传递到“.../access_token”端点,从那里获取令牌。有了这个令牌,他们就可以调用其他端点。

在新的 api 版本中,我将 AWS Api Gateway 与 Authorizer 结合使用。我想根据用户名和密码字段提供对资源的访问权限。

我创建了一个用户池并在其中添加了我的用户。如何仅使用 api 端点进行身份验证?
我无法使用 Oauth“客户端凭据”流程,因为它是机器到机器的,客户端机密将被暴露。

在授权代码或隐式授权中,我必须要求用户登录 AWS/自定义 ui 并获得重定向。所以我不能在 Api 中使用这些。

我错过了什么?

amazon-web-services aws-api-gateway amazon-cognito
2个回答
2
投票

我了解您需要在不使用浏览器的情况下对用户进行身份验证。一个想法是创建一个登录端点,用户将在其中提供他们的用户名和密码并取回令牌。您应该自己实现此端点。来自这个问题

aws cognito-idp admin-initiate-auth --region {your-aws-region} --cli-input-json file://auth.json

auth.json 所在位置:

{
    "UserPoolId": "{your-user-pool-id}",
    "ClientId": "{your-client-id}",
    "AuthFlow": "ADMIN_NO_SRP_AUTH",
    "AuthParameters": {
        "USERNAME": "[email protected]",
        "PASSWORD": "password123"
    }
}

这将为您的用户提供访问权限、ID 和刷新令牌(与授权授予类型相同的方式)。他们应该能够使用访问令牌来访问资源,并针对令牌端点使用刷新令牌来更新访问令牌。

这不是验证 API 的常用方法,并且可能会产生一些安全隐患。


0
投票

我通过在 NodeJS 16x 中使用公开的 URL 创建自定义 Lambda 解决了这个问题,它使用存储的应用程序客户端 ID、用户池 ID、秘密在 Cognito 端进行基本身份验证。我在此处附加了代码,但您仍然需要使用 Cognito SDK 创建 lambda 层,并自行配置 IAM。

const AWS = require('aws-sdk');
const {
  CognitoIdentityProviderClient,
  AdminInitiateAuthCommand,
} = require("/opt/nodejs/node16/node_modules/@aws-sdk/client-cognito-identity-provider");
const client = new CognitoIdentityProviderClient({ region: "eu-central-1" });
exports.handler = async (event, context, callback) => {
    
    let username = event.queryStringParameters.username;
    let password = event.queryStringParameters.password;
    let app_client_id = process.env.app_client_id;
    let app_client_secret = process.env.app_client_secret;
    let user_pool_id = process.env.user_pool_id;
    let hash = await getHash(username, app_client_id, app_client_secret);
        
    let auth = {
        "UserPoolId": user_pool_id,
        "ClientId": app_client_id,
        "AuthFlow": "ADMIN_NO_SRP_AUTH",
        "AuthParameters": {
            "USERNAME": username,
            "PASSWORD": password,
            "SECRET_HASH": hash
        }
    };
let cognito_response = await requestToken(auth);
var lambda_response;
    if (cognito_response.startsWith("Error:")){
        lambda_response = {
          statusCode: 401,
          body: JSON.stringify(cognito_response) + "\n input: username = " + username + " password = " + password,
        };
    }
    else {
      lambda_response = {
        statusCode: 200,
        body: JSON.stringify("AccessToken = " + cognito_response),
      };
    }
    return lambda_response;
};
async function getHash(username, app_client_id, app_client_secret){
    const { createHmac } = await import('node:crypto');
    let msg = new TextEncoder().encode(username+app_client_id);
    let key = new TextEncoder().encode(app_client_secret);
    const hash = createHmac('sha256', key)  // TODO should be separate function
               .update(msg)
               .digest('base64');
    return hash;
}
async function requestToken(auth) {
  const command = new AdminInitiateAuthCommand(auth);  
    var authResponse;
  try {
    authResponse = await client.send(command);
  } catch (error) {
    return "Error: " + error;
  }
  return authResponse.AuthenticationResult.AccessToken;
}
© www.soinside.com 2019 - 2024. All rights reserved.