Cognito:将文件从S3上传到S3到自定义用户子文件夹

时间:2019-04-07 07:46:27

标签: php amazon-web-services amazon-s3 amazon-cognito amazon-iam

这部分是问题,部分是我遇到的一些问题。 问题在底部。

我想使用Cognito从浏览器直接将文件上传到S3。它与未经身份验证的用户一起使用时效果很好,但是每个用户都可以访问相同的存储桶或至少相同的文件夹。我希望每个用户只能访问他们的文件夹。

经过三天的头部撞击,我得以在一个紧凑的php文件中使Cognito与使用JavaScript和PHP的自定义开发人员验证身份一起工作。

在服务器上,我使用getOpenIdTokenForDeveloperIdentity接收IdentityIdToken作为用户名johnsmith

然后我立即将ID和令牌提供给客户端以对其进行身份验证,然后将文件上传到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权限政策是借来的from here,看起来像这样:

{
  "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}以外的自定义子文件夹 我发现this article表明可以使用${aws:username}/*,但是如何将用户名传递给OpenID令牌或其他地方?

2 个答案:

答案 0 :(得分:1)

不幸的是,这是不可能的。您看到的用户名变量仅适用于IAM用户名。 IAM策略无法从Cognito用户池读取任何内容。您看到的子变量与用户池中显示的子变量完全不同。该子实际上来自身份池,该身份池没有任何用户名。也许AWS将来会允许这样做,但是目前这是不可能的。

但是,您可以在创建应用程序时将其隐藏在用户面前。如果您通过控制台登录,则只会在存储区路径中看到此大子变量。我建立了一个类似的应用程序,我只向用户显示此变量中的所有内容,就好像它是其根文件夹一样。

答案 1 :(得分:1)

用户名没有IAM策略变量,但是如果您想花点力气,我想您可以做些事。

  1. 更新Lambda。使用Cognito SDK进行ListUsers。您可以提供子项并找回用户名。将数据写入格式为mybucket/username/sub
  2. 的文件夹中
  3. 更新存储桶策略,将通配符放在用户名所在的位置。

例如:

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

您仍将sub作为文件夹名称,但是它位于用户名文件夹下,因此浏览该文件夹将很容易。