Cognito: загрузить файл на S3 в пользовательскую подпапку из браузера - PullRequest
1 голос
/ 07 апреля 2019

Это частичный вопрос, частично ответ на некоторые вопросы, с которыми я боролся. Вопрос внизу.

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

После 3 дней головокружения я смог заставить Cognito работать с индивидуальными идентификационными данными разработчика, использующими JavaScript и PHP, в одном компактном php-файле.

На сервере я использую getOpenIdTokenForDeveloperIdentity для получения IdentityId и Token для имени пользователя johnsmith.

Затем я немедленно предоставляю клиенту идентификатор и токен для аутентификации и загружаю файл на S3:

<!-- BEGIN SERVER SIDE -->
<?php
session_start();

//Include AWS client libs
require ('vendor/autoload.php');
use Aws\CognitoIdentity\CognitoIdentityClient;
use Aws\Sts\StsClient;

/* Global Vars */
$aws_region = 'us-east-1';
$aws_key = 'JF4L3ELC4CAVQV4VAKIA';
$aws_secret = 'OKfoWZ91qZHBhIBzDZLINzHVs9Ymaxi689Ym3vT8';
$identity_pool_id = 'us-east-1:83024a7c-438e-aa29-8bac-ff6717d73ec5';

//Initialize a Cognito Identity Client using the Factory
$client = CognitoIdentityClient::factory(array('region' => $aws_region, 'key' => $aws_key, 'secret' => $aws_secret));

/* Acquire new Identity */
$identity = $client->getOpenIdTokenForDeveloperIdentity(array('IdentityPoolId' => $identity_pool_id, 'Logins' => array('my-custom-login' => 'johnsmith')));

//Obtain Identity from response data structure
$id = $identity->get('IdentityId');
$token = $identity->get('Token');

print_r($identity);
// Results in:
// [IdentityId] => us-east-1:c4db3eca-6ed0-af08-4aaa-a33aee2e994a
// [Token] => eyJraWQiOiJ1cy1lYXN0LTExIiwidHlwIjoiSldTIiwiYWxnIjoiUlM1MTIifQ.eyJzd...
?>

<!-- BEGIN CLIENT SIDE -->

<script src="https://sdk.amazonaws.com/js/aws-sdk-2.436.0.min.js"></script>

<script>
var bucketName = 'mybucket';

//Get CognitoIdentityCredentials
AWS.config.region = 'us-east-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityId: '<?php echo $id; ?>',
    IdentityPoolId: '<?php echo $identity_pool_id; ?>',
        Logins: {
            //'my-custom-login':'johnsmith', //This does not work. It throws Error 400: Please provide a valid public provider.
            'cognito-identity.amazonaws.com':'<?php echo $token; ?>'
        }
});

//S3 Upload
var s3 = new AWS.S3({
    //region: 'us-east-1', //Bucket region - not required if same as AWS.config.region
    apiVersion: '2006-03-01',
    params: {Bucket: bucketName}
});


//Refresh and Upload
AWS.config.credentials.refresh(function(){

    var IdentityId = s3.config.credentials.params.IdentityId;
    var keyName = "cognito/"+IdentityId+"/it_works.txt";
    var params = {Bucket: bucketName, Key: keyName, Body: 'Hello World!'};
    s3.putObject(params, function (err, data) {
    if (err)
            console.log(err)
        else
            console.log("Successfully uploaded data to " + bucketName + "/" + keyName);
    });
});

//Console: Successfully uploaded data to mybucket/cognito/us-east-1:c4db3eca-6ed0-af08-4aaa-a33aee2e994a/it_works.txt);
</script>

Моя политика разрешений IAM была заимствована отсюда и выглядит следующим образом:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": ["s3:ListBucket"],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::mybucket"],
      "Condition": {"StringLike": {"s3:prefix": ["${cognito-identity.amazonaws.com:sub}/*"]}}
    },
    {
      "Action": [
        "s3:GetObject",
        "s3:PutObject"
      ],
      "Effect": "Allow",
      "Resource": ["arn:aws:s3:::mybucket/${cognito-identity.amazonaws.com:sub}/*"]
    }
  ]
}

Это все прекрасно работает и загружает файл в mybucket/cognito/us-east-1:c4db3eca-6ed0-af08-4aaa-a33aee2e994a/it_works.txt

Я хотел установить пользовательскую подпапку с именем пользователя johnsmith.

Мой вопрос:

Есть ли способ передать имя пользователя как переменную, которая будет использоваться в качестве разрешения роли IAM, чтобы он мог загружать в mybucket/cognito/johnsmith/ вместо этого уродливого и длинного mybucket/cognito/us-east-1:c4db3eca-6ed0-af08-4aaa-a33aee2e994a/?

Эти IdentityIds слишком длинные и с ними трудно иметь дело. Я думаю, мне придется сохранить IdentityId в моей базе данных?

Является ли информация в токене "декодируемой" или это просто безопасный хеш. Я заметил, что при обновлении меняется только вторая половина, а при смене имени пользователя меняется весь токен.

Пожалуйста, дайте мне знать, как настроить пользовательскую подпапку с Cognito, кроме IdentityId ${cognito-identity.amazonaws.com:sub} Я нашел эту статью , в которой показано, что вы можете использовать ${aws:username}/*, но как передать имя пользователя в OpenID Token или где-то еще?

Ответы [ 2 ]

1 голос
/ 09 апреля 2019

Не существует переменной политики IAM для имени пользователя, но если вы хотите приложить некоторые усилия, я думаю, вы могли бы заставить что-то работать.

  1. Обновление лямбды. Используйте Cognito SDK для создания ListUsers . Вы можете предоставить саб и получить имя пользователя обратно. Записать данные в папку с форматом mybucket/username/sub
  2. Обновите политику корзины, поместив подстановочный знак, где указано имя пользователя.

например:

Resource": ["arn:aws:s3:::mybucket/*/${cognito-identity.amazonaws.com:sub}/*"]

У вас все равно будет sub в качестве имени папки, но оно будет находиться в папке с именем пользователя, поэтому просмотр папки будет простым.

1 голос
/ 08 апреля 2019

К сожалению, это невозможно.Переменная username, которую вы видите, применяется только к именам пользователей IAM.Политика IAM не может читать что-либо из пула пользователей Cognito.Переменная, которую вы видите, полностью отличается от переменной, которая появляется в пуле пользователей.Подпрограмма фактически происходит из пула идентификаторов, который не имеет никакого имени пользователя.Возможно, AWS позволит это в будущем, но в настоящее время это невозможно.

Однако вы можете просто скрыть это от пользователей при создании приложений.Вы увидите эту большую суб-переменную в пути, только если войдете через консоль.Я создал похожее приложение, в котором я просто показываю пользователям все внутри этой переменной, как если бы это была их корневая папка.

...