带有 Cognito 的 AWS Lambda API 网关 - 如何使用 IdentityId 访问和更新 UserPool 属性? [英] AWS Lambda API gateway with Cognito - how to use IdentityId to access and update UserPool attributes?

查看:28
本文介绍了带有 Cognito 的 AWS Lambda API 网关 - 如何使用 IdentityId 访问和更新 UserPool 属性?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

好的,我现在已经研究了几天并取得了重大进展,但我仍然对基本面感到困惑.

OK I am now days into this and have made significant progress but am still completely stumped about the fundamentals.

我的应用程序使用 Cognito 用户池来创建和管理用户 - 这些在 S3 上通过他们的 IdentityId 进行标识.我的每个用户都有自己的 S3 文件夹,AWS 会自动为他们提供一个与用户的 IdentityId 相同的文件夹名称.

My application uses Cognito User Pools for creating and managing users - these are identified on S3 it seems by their IdentityId. Each of my users has their own S3 folder, and AWS automatically gives them a folder name that is equal to the user's IdentityId.

我需要将 IdentityId 与其他 Cognito 用户信息相关联,但不知道如何做.

I need to relate the IdentityId to the other Cognito user information but cannot work out how.

我需要的关键是能够识别给定 IdentityId 的用户名和其他认知用户属性 - 这非常困难.

The key thing I need is to be able to identify the username plus other cognito user attributes for a given IdentityId - and it's insanely hard.

因此,第一场战斗是弄清楚当 Cognito 用户通过 AWS API 网关发出请求时如何获取 IdentityId.最终我解决了这个问题,现在我有一个 Cognito 用户,他向 API 网关发出请求,而我背后的 Lambda 函数现在有了 IdentityId.那一点管用.

So the first battle was to work out how to get the IdentityId when a Cognito user does a request via the AWS API Gateway. Finally I got that worked out, and now I have a Cognito user, who does a request to the API Gateway, and my Lambda function behind that now has the IdentityId. That bit works.

但是我完全不知道现在如何访问存储在用户池中的 Cognito 用户信息.我找不到任何明确的信息,当然也没有代码,说明如何使用 IdentityId 获取 Cognito 用户的属性、用户名等.

But I am completely stumped as to how to now access the Cognito user's information that is stored in the user pool. I can't find any clear information, and certainly no code, that shows how to use the IdentityId to get the Cognito user's attributes, username etc.

看来,如果我在 API Gateway 中使用Cognito 用户池"来授权我的方法,那么可以使用正文映射模板将 Cognito 用户信息(例如 sub 和用户名和电子邮件地址)放入上下文中,但我没有得到 IdentityId.

It appears that if I use a "Cognito user pool" to authorize my method in API Gateway, then the body mapping template can be used to put Cognito User information such as the sub and the username and email address into the context, BUT I do NOT get the IdentityId.

但是,如果我使用 AWS_IAM 在 API 网关中授权我的方法,则主体映射模板会执行相反的操作 - 它为我提供 IdentityId 而不是 Cognito 用户字段,例如 sub 和 username 以及电子邮件.

BUT if I use the AWS_IAM to authorize my method in the API gateway then the body mapping template does the inverse - it gives me the IdentityId but not the Cognito user fields such as sub and username and email.

这让我很抓狂 - 如何将 IdentityId 和所有 Cognito 用户字段和属性整合到一个数据结构中?我似乎只能得到其中一个这一事实毫无意义.

It's driving me crazy - how can I get the IdentityId and all the Cognito users fields and attributes together into one data structure? The fact that I seem to be only able to get one or the other just makes no sense.

推荐答案

事实证明,要使用 AWS Lambda/Cognito/API Gateway 同时获取 IdentityId 和用户详细信息,您需要有一个 Lambda 函数使用 AWS_IAM(不是 COGNITO_USER_POOLS)进行身份验证,您必须将您的请求发送到 AWS API 网关,但它必须是一个签名的请求,然后您必须修改集成请求正文映射模板以便在事件中为您提供 IdentityId(可能是上下文?不记得了).现在您有了 IdentityId.呼.现在您必须从前端向后端提交客户端的 Cognito ID 令牌.验证令牌很重要 - 如果您不验证它,您就不能相信它没有被篡改.要解码和验证令牌,您必须从用户池中获取密钥,将它们放入脚本中,确保您的 AWS lambda zipfile 中包含 jwt 解码库和签名验证库.现在您的脚本必须验证从前端提交的令牌,然后您可以从令牌中获取用户详细信息.瞧!现在您拥有 IdentityId 以及用户详细信息,例如他们的子、用户名和电子邮件地址.如此简单.

It turns out that to get the IdentityId AND user details at the same time using AWS Lambda/Cognito/API Gateway, you need to have a Lambda function that is authenticated using AWS_IAM (NOT COGNITO_USER_POOLS), you must send your request the AWS API Gateway, BUT it MUST be a signed request, you must then modify the integration request body mapping templates so that you are given the IdentityId in the event (maybe the context? can't remember). Now you have the IdentityId. Phew. Now you must submit the client's Cognito ID token from the front end to the back end. It is important to validate the token - you cannot trust that it has not been tampered with if you do not validate it. To decode and validate the token you must get the keys from your userpool, put them into your script, ensure that you have jwt decoding libraries plus signature validation libraries included in your AWS lambda zipfile. Now your script must validate the token submitted from the front end and then you can get the user details out of the token. Voila! Now you have both IdentityId plus user details such as their sub, username and email address. So easy.

以上是使用 AWS Cognito/Lambda/API Gateway 获取与 IdentityId 关联的用户名所需的操作.这花了我几天的时间才开始工作.

The above is what is takes to get the username associated with an IdentityId using AWS Cognito/Lambda/API Gateway. This took me days to get working.

我可以对任何遇到此问题的亚马逊员工说一下吗......好吧,获取与 IdentityId 相关联的用户详细信息太难了.你需要解决这个问题.这让我很生气,因为这太难了,浪费了我太多的时间.

Can I please say to any Amazon employees who wander across this ........ well it's WAY too hard to get the user details associated with an IdentityId. You need to fix this. It made me angry that this was so hard and burned so much of my time.

解决办法:

我通过在此处修改 Amazon 员工自定义授权方来实现此目的:https://s3.amazonaws.com/cup-resources/cup_custom_authorizer_lambda_function_blueprint.zip

I did this by modifying an Amazon employees custom authorizer here: https://s3.amazonaws.com/cup-resources/cup_custom_authorizer_lambda_function_blueprint.zip

在此处找到并描述:https://aws.amazon.com/blogs/mobile/integrating-amazon-cognito-user-pools-with-api-gateway/

use strict';
let util = require('util');

var jwt = require('jsonwebtoken'); 
var jwkToPem = require('jwk-to-pem');

var userPoolId = 'YOUR USERPOOL ID';
var region = 'YOUR REGION'; //e.g. us-east-1
var iss = 'https://cognito-idp.' + region + '.amazonaws.com/' + userPoolId;

//https://docs.aws.amazon.com/cognito/latest/developerguide/amazon-cognito-user-pools-using-tokens-with-identity-providers.html
// DOWNLOAD FROM https://cognito-idp.{region}.amazonaws.com/{userPoolId}/.well-known/jwks.json
let userPoolKeys = {PUT YOUR DOWNLOADED USER POOL KEYS JSON HERE};
var pems = {};

let convertKeysToPems = () => {
    var keys = userPoolKeys['keys'];
    for(var i = 0; i < keys.length; i++) {
        //Convert each key to PEM
        var key_id = keys[i].kid;
        var modulus = keys[i].n;
        var exponent = keys[i].e;
        var key_type = keys[i].kty;
        var jwk = { kty: key_type, n: modulus, e: exponent};
        var pem = jwkToPem(jwk);
        pems[key_id] = pem;
    }
}

exports.handler = function(event, context) {

    convertKeysToPems()
    console.log(event);
    let token = event['body-json'].cognitoUserToken;
    console.log(event['body-json'].cognitoUserToken);
    ValidateToken(pems, event, context, token);

};


let ValidateToken = (pems, event, context, token) => {

    //Fail if the token is not jwt
    var decodedJwt = jwt.decode(token, {complete: true});
        console.log(decodedJwt)
    if (!decodedJwt) {
        console.log("Not a valid JWT token");
        context.fail("Unauthorized");
        return;
    }

    //Fail if token is not from your UserPool
    if (decodedJwt.payload.iss != iss) {
        console.log("invalid issuer");
        context.fail("Unauthorized");
        return;
    }

    //Reject the jwt if it's not an 'Access Token'
    if (decodedJwt.payload.token_use != 'id') {
        console.log("Not an id token");
        context.fail("Unauthorized");
        return;
    }

    //Get the kid from the token and retrieve corresponding PEM
    var kid = decodedJwt.header.kid;
    var pem = pems[kid];
    if (!pem) {
        console.log(pems, 'pems');
        console.log(kid, 'kid');
        console.log('Invalid token');
        context.fail("Unauthorized");
        return;
    }

    //Verify the signature of the JWT token to ensure it's really coming from your User Pool

    jwt.verify(token, pem, { issuer: iss }, function(err, payload) {
      if(err) {
        context.fail("Unauthorized");
      } else {
        let x = decodedJwt.payload
        x.identityId = context.identity.cognitoIdentityId
        //let x = {'identityId': context['cognito-identity-id'], 'decodedJwt': decodedJwt}
        console.log(x);
        context.succeed(x);
      }
    });
}

这篇关于带有 Cognito 的 AWS Lambda API 网关 - 如何使用 IdentityId 访问和更新 UserPool 属性?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆