AWS Lambda API-шлюз с Cognito - как использовать IdentityId для доступа и обновления атрибутов UserPool?

ОК. Сейчас я занимаюсь этим и добился значительного прогресса, но я все еще полностью озадачен фундаментальными принципами.

Мое приложение использует Cognito User Pools для создания и управления пользователями - они идентифицированы на S3, кажется, их IdentityId. Каждый из моих пользователей имеет свою собственную папку S3, и AWS автоматически дает им имя папки, которое равно идентификатору пользователя IdentityId.

Мне нужно связать IdentityId с другой информацией пользователя Cognito, но не могу понять, как это сделать.

Ключевая вещь, которая мне нужна, - это определить имя пользователя и другие атрибуты пользователя cognito для данного IdentityId - и это безумно сложно.

Итак, первая битва заключалась в том, чтобы выяснить, как получить IdentityId, когда пользователь Cognito выполняет запрос через AWS API Gateway. Наконец, я получил это, и теперь у меня есть пользователь Cognito, который выполняет запрос к Gateway API, а моя функция Lambda позади этого теперь имеет IdentityId. Этот бит работает.

Но я полностью зациклен на том, как теперь получить доступ к информации пользователя Cognito, которая хранится в пуле пользователей. Я не могу найти никакой четкой информации и, конечно, никакого кода, который показывает, как использовать IdentityId для получения пользовательских атрибутов Cognito, имени пользователя и т.д.

Похоже, что если я использую "пул пользователей Cognito" для авторизации моего метода в шлюзе API, то шаблон сопоставления тела можно использовать для размещения информации пользователя Cognito User, такой как sub и имя пользователя и адрес электронной почты, в контексте, НО Я НЕ получаю IdentityId.

НО, если я использую AWS_IAM для авторизации моего метода в шлюзе API, тогда шаблон отображения тела обратный - он дает мне IdentityId, но не поля пользователя Cognito, такие как имя суб и имя пользователя и адрес электронной почты.

Это сводит меня с ума - как я могу получить IdentityId и все поля и атрибуты пользователей Cognito вместе в одну структуру данных? Тот факт, что я, кажется, только могу получить тот или другой, просто не имеет смысла.

Ответ 1

Оказалось, что для одновременного получения идентификационных данных IdentityId AND с использованием AWS Lambda/Cognito/API Gateway вам необходимо иметь функцию Lambda, которая аутентифицируется с использованием AWS_IAM (NOT COGNITO_USER_POOLS), вы должны отправить запрос AWS API Gateway, НО ДОЛЖЕН быть подписанным запросом, вы должны затем модифицировать шаблоны сопоставления тела запроса интеграции, чтобы вам дали IdentityId в событии (возможно, контекст? Не помню). Теперь у вас есть IdentityId. Уф. Теперь вы должны отправить токен клиента Cognito ID с переднего конца на задний конец. Важно проверить токен - вы не можете доверять, что он не был изменен, если вы его не проверяете. Чтобы декодировать и проверять токен, вы должны получить ключи из своего пользовательского пула, поместить их в свой script, убедитесь, что у вас есть jwt-декодирующие библиотеки и библиотеки проверки подписей, включенные в ваш zms файл AWS lambda. Теперь ваш script должен проверить маркер, отправленный с лицевой стороны, и затем вы можете получить данные пользователя из токена. Вуаля! Теперь у вас есть и IdentityId плюс данные пользователя, такие как их под, имя пользователя и адрес электронной почты. Так легко.

Вышеупомянутое - это то, что требуется, чтобы получить имя пользователя, связанное с IdentityId, используя AWS Cognito/Lambda/API Gateway. Мне потребовались дни, чтобы работать.

Могу ли я сказать любым работникам Amazon, которые бродят по этому........ хорошо, что слишком сложно получить информацию о пользователе, связанную с IdentityId. Вам нужно это исправить. Меня разозлило, что это так тяжело и сожжено так много времени.

Решение:

Я сделал это, изменив пользовательский авторизованный пользователь Amazon: 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 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 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);
      }
    });
}