#php #amazon-web-services #amazon-s3 #amazon-cognito #amazon-iam
#php #amazon-веб-сервисы #amazon-s3 #amazon-cognito #amazon-iam
Вопрос:
Это частично вопрос, частично отвечающий на некоторые проблемы, с которыми я боролся. Вопрос внизу.
Я хотел загрузить файл прямо из браузера на 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 AwsCognitoIdentityCognitoIdentityClient;
use AwsStsStsClient;
/* 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/
?
Эти идентификаторы слишком длинные, и с ними сложно иметь дело. Полагаю, мне также придется сохранить identityId в моей базе данных?
Является ли информация в токене «декодируемой» или это просто безопасный хэш. Я заметил, что при обновлении меняется только вторая его половина, а когда я меняю имя пользователя, меняется весь токен.
Пожалуйста, дайте мне знать, как настроить пользовательскую подпапку с Cognito, отличную от identityId ${cognito-identity.amazonaws.com:sub}
Я нашел эту статью, в которой показано, что вы можете использовать ${aws:username}/*
, но как мне передать имя пользователя в OpenID Token или где-то еще?
Ответ №1:
Для имени пользователя нет переменной политики IAM, но если вы захотите приложить некоторые усилия, я думаю, вы могли бы заставить что-то работать.
- Обновите лямбда. Используйте Cognito SDK для создания списка пользователей. Вы можете указать подпапку и получить имя пользователя обратно. Записать данные в папку с форматом
mybucket/username/sub
- Обновите политику корзины, поместив подстановочный знак вместо имени пользователя.
например:
Resource": ["arn:aws:s3:::mybucket/*/${cognito-identity.amazonaws.com:sub}/*"]
У вас все равно будет sub
в качестве имени папки, но оно будет находиться в папке username, поэтому просмотр папки будет простым.
Ответ №2:
К сожалению, это невозможно. Переменная username, которую вы видите, применяется только к именам пользователей IAM. Политика IAM не может ничего прочитать из пула пользователей cognito. Переменная sub, которую вы видите, полностью отличается от переменной sub, которая отображается в user pool. Вложенный файл фактически поступает из пула удостоверений, в котором нет имени пользователя. Возможно, AWS разрешит это в будущем, но в настоящее время это невозможно.
Однако вы можете просто скрыть это от пользователей при создании приложений. Вы увидите эту большую переменную sub в bucket path только в том случае, если вы войдете в систему через консоль. Я создал аналогичное приложение, где я просто показываю пользователям все внутри этой переменной, как будто это их корневая папка.