web-dev-qa-db-ja.com

Cognitoを使用したAWS Lambda APIゲートウェイ-IdentityIdを使用してUserPool属性にアクセスして更新する方法

OK私は今、これに何日もかかっており、重要な進歩を遂げましたが、それでも基礎については完全に困惑しています。

私のアプリケーションは、ユーザーの作成と管理にCognitoユーザープールを使用します。これらは、IdentityIdによってS3で識別されます。各ユーザーには独自のS3フォルダーがあり、AWSはユーザーのIdentityIdと同じフォルダー名を自動的に与えます。

IdentityIdを他のCognitoユーザー情報に関連付ける必要がありますが、その方法はわかりません。

私が必要とする重要なことは、特定のIdentityIdのユーザー名と他のコグニトユーザー属性を識別できるようにすることです-それはめちゃくちゃ難しいです。

したがって、最初の戦いは、CognitoユーザーがAWS API Gatewayを介してリクエストを行ったときにIdentityIdを取得する方法を見つけることでした。最後に、それがうまくいったので、API Gatewayにリクエストを送信するCognitoユーザーがいます。その背後にあるLambda関数にはIdentityIdがあります。そのビットは動作します。

しかし、ユーザープールに保存されているCognitoユーザーの情報にアクセスする方法については、完全に困惑しています。 IdentityIdを使用してCognitoユーザーの属性、ユーザー名などを取得する方法を示す明確な情報が見つかりません。確かにコードも見つかりません。

「Cognitoユーザープール」を使用してAPI Gatewayでメソッドを認証する場合、ボディマッピングテンプレートを使用して、Sub、ユーザー名、メールアドレスなどのCognitoユーザー情報をコンテキストに入れることができますが、 IdentityIdを取得しません。

ただし、AWS_IAMを使用してAPIゲートウェイでメソッドを承認すると、ボディマッピングテンプレートは逆になります。IdentityIdを提供しますが、Sub、Username、EmailなどのCognitoユーザーフィールドは提供しません。

それは私を夢中にさせます-IdentityIdとすべてのCognitoユーザーのフィールドと属性を1つのデータ構造にまとめるにはどうすればよいですか?どちらか一方しか取得できないように見えるという事実は、まったく意味をなさない。

32
Duke Dougal

AWS Lambda/Cognito/API Gatewayを使用してIdentityIdとユーザー詳細を同時に取得するには、AWS_IAMCOGNITO_USER_POOLSではなく)を使用して認証されるLambda関数が必要です。 AWS API Gatewayにリクエストを送信する必要がありますが、署名されたリクエストである必要があります。次に、イベントでIdentityIdが与えられるように、統合リクエスト本文マッピングテンプレートを変更する必要があります(コンテキストを覚えていないかもしれません)。これでIdentityIdができました。ふう。ここで、クライアントのCognito IDトークンをフロントエンドからバックエンドに送信する必要があります。トークンを検証することは重要です-トークンを検証しないと、改ざんされていないことを信頼できません。トークンをデコードおよび検証するには、ユーザープールからキーを取得し、スクリプトに挿入し、jwtデコードライブラリと署名検証ライブラリがAWSラムダzipファイルに含まれていることを確認する必要があります。これで、スクリプトはフロントエンドから送信されたトークンを検証する必要があり、トークンからユーザーの詳細を取得できます。出来上がり!これで、IdentityIdと、サブ、ユーザー名、電子メールアドレスなどのユーザー詳細の両方が得られました。とても簡単。

上記は、AWS Cognito/Lambda/API Gatewayを使用してIdentityIdに関連付けられたユーザー名を取得するために必要なことです。これは私が仕事をするのに数日かかりました。

これをさまよう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'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);
      }
    });
}
36
Duke Dougal