with cognito aws-lambda aws-api-gateway amazon-cognito
https://s3.amazonaws.com/cup-resources/cup_custom_authorizer_lambda_function_blueprint.zip

aws-lambda - amazon api gateway with cognito



AWS Lambda API gateway con Cognito: ¿cómo utilizar IdentityId para acceder y actualizar los atributos de UserPool? (2)

OK, ahora tengo días en esto y he hecho un progreso significativo, pero todavía estoy completamente confundido con los fundamentos.

Mi aplicación utiliza los grupos de usuarios de Cognito para crear y administrar usuarios; estos se identifican en S3 según parece su IdentityId. Cada uno de mis usuarios tiene su propia carpeta S3, y AWS les da automáticamente un nombre de carpeta que es igual al IdentityId del usuario.

Necesito relacionar IdentityId con la información del otro usuario de Cognito, pero no puedo averiguar cómo.

La clave que necesito es poder identificar el nombre de usuario más otros atributos de usuario de cognito para un IdentityId determinado, y es increíblemente difícil.

Así que la primera batalla fue averiguar cómo obtener el IdentityId cuando un usuario de Cognito realiza una solicitud a través de la puerta de enlace de la API de AWS. Finalmente conseguí que funcionara, y ahora tengo un usuario de Cognito, que hace una solicitud a la API Gateway, y mi función Lambda detrás de eso ahora tiene el IdentityId. Ese poco funciona.

Pero estoy completamente perplejo en cuanto a cómo acceder ahora a la información del usuario de Cognito que está almacenada en el grupo de usuarios. No puedo encontrar ninguna información clara, y ciertamente ningún código, que muestre cómo usar IdentityId para obtener los atributos, el nombre de usuario, etc. de Cognito.

Parece que si uso un "grupo de usuarios de Cognito" para autorizar mi método en la puerta de enlace de la API, entonces la plantilla de mapeo del cuerpo se puede usar para poner información de usuario de Cognito como el sub y el nombre de usuario y la dirección de correo electrónico en el contexto, PERO NO obtener el ID de identidad.

PERO si uso el AWS_IAM para autorizar mi método en la puerta de enlace de la API, entonces la plantilla de mapeo del cuerpo hace lo inverso: me da el IdentityId pero no los campos de usuario de Cognito, como sub y username y email.

Me estoy volviendo loco. ¿Cómo puedo reunir los campos y atributos de IdentityId y todos los usuarios de Cognito en una sola estructura de datos? El hecho de que parezca que solo soy capaz de obtener uno u otro simplemente no tiene sentido.


Resulta que para obtener los datos de IdentityId AND usuario al mismo tiempo que usa AWS Lambda / Cognito / API Gateway, debe tener una función Lambda que se autentique mediante AWS_IAM (NO COGNITO_USER_POOLS ), debe enviar su solicitud a AWS API Gateway , PERO DEBE ser una solicitud firmada, luego debe modificar las plantillas de mapeo del cuerpo de la solicitud de integración para que se le proporcione el IdentityId en el evento (tal vez el contexto no pueda recordarlo). Ahora tienes el ID de identidad. Uf. Ahora debe enviar el token de ID de Cognito del cliente desde el extremo frontal al extremo posterior. Es importante validar el token: no puede confiar en que no haya sido manipulado si no lo valida. Para decodificar y validar el token, debe obtener las claves de su grupo de usuarios, ponerlas en su script, asegurarse de tener bibliotecas de decodificación jwt más bibliotecas de validación de firmas incluidas en su archivo zip AWS lambda. Ahora su script debe validar el token enviado desde el front-end y luego puede obtener los detalles del usuario fuera del token. Voila! Ahora tiene los dos datos de identificación de usuario de IdentityId plus, como su sub, nombre de usuario y dirección de correo electrónico. Tan fácil.

Lo anterior es lo que se necesita para obtener el nombre de usuario asociado con un IdentityId mediante AWS Cognito / Lambda / API Gateway. Esto me tomó días para ponerme a trabajar.

¿Puedo decirle a cualquier empleado de Amazon que pase por esto ...? Bueno, es demasiado difícil obtener los detalles de usuario asociados con un IdentityId. Necesitas arreglar esto. Me enojé porque esto era tan difícil y quemó gran parte de mi tiempo.

La solución:

Hice esto modificando un autorizador personalizado de los empleados de Amazon aquí: https://s3.amazonaws.com/cup-resources/cup_custom_authorizer_lambda_function_blueprint.zip

tal como se encuentra y describe aquí: 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); } }); }


Si entiendo esto correctamente, querrá los CognitoIdentityId y User en el mismo lugar. Como lo hacemos es de la siguiente manera:

Del contexto de solicitud de evento obtenemos el IdentityId: event.requestContext.identity.cognitoIdentityId

También del contexto de la solicitud obtenemos el usuario sub: event.requestContext.identity.cognitoAuthenticationProvider.split('':CognitoSignIn:'')[1]

Luego con el sub puede solicitar el resto de los atributos de la siguiente manera:

const AWS = require(''aws-sdk''); let cognito = new AWS.CognitoIdentityServiceProvider(); let request = { Username: userSub, UserPoolId: process.env.userPoolId, }; let result = await cognito.adminGetUser(request).promise(); const userAttributes = result.UserAttributes.reduce((acc, attribute) => { const { Name, Value } = attribute; acc[Name] = Value; return acc; }, {}); return userAttributes;