2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

【PHP・AWS】AWS Cognitoを通してS3にアップロードする方法

Posted at

はじめに

PHPでAWS Cgnito認証を通してAWS認証情報を所得してS3を使用する記事が少なかったので、自分の備忘録としても記事に残したいと思います。
※あると程度AWSやCognitoを知っている程でいきます😅

環境

下記のものをcomposerでインストールしておきます。

aws/aws-sdk-php: 3.26.3
pmill/aws-cognito: ^0.2.11

PHPのバージョンは 7.4.1 です。

Cognito

ユーザプールの作成

スクリーンショット 2020-08-27 23.42.23.png
適当にプール名を入れて、「ステップに従って設定する」を選択しましょう。

スクリーンショット 2020-08-29 13.27.06.png
属性を設定し、ポリシーでパスワードの強度を設定したら今回は凝った設定はしませんので、アプリクライアントの設定に進みましょう。

スクリーンショット 2020-08-27 23.48.02.png
アプリクライアント名をいれて、
スクリーンショット 2020-08-29 14.04.32.png
「認証用の管理APIのユーザー名パスワード認証、、、」にチェックをしておきましょう。
スクリーンショット 2020-08-29 14.08.35.png
確認まで進んで、プールの作成をします。

IDプール(フェデレーティッドアイデンティティ)の作成

スクリーンショット 2020-08-28 22.22.38.png
適当なIDプール名を入れて、
スクリーンショット 2020-08-28 22.22.44.png
Cognitoのユーザーで認証を通すため、先ほど作成したユーザープールのIDとアプリクライアントのIDを入力し、プールの作成をします。

ユーザープールのIDは「全般設定」から見れます。
スクリーンショット 2020-08-28 22.21.36.png
クライアントIDは「全般設定のアプリクライアント」から見れます。
スクリーンショット 2020-08-28 22.22.07.png

スクリーンショット 2020-08-28 22.23.02.png
ここで認証を通したユーザーに対して適応するIAM ロールを作成しろと言われるので作成します。
ついでにCognitoのIAMユーザーも作っておきましょう。

ユーザープールでユーザーの作成

Cognitoにログインできるユーザーを作成しておきましょう。
スクリーンショット 2020-08-28 22.51.53.png
「ユーザー&グループ」を選択してユーザーの作成を選択しましょう。
スクリーンショット 2020-08-28 23.08.56.png
使用するユーザーのメールアドレスを入力しユーザーの作成をします。
作成できたら、
スクリーンショット 2020-08-29 16.02.51.png
こんな感じで確認できると思います。

Congitoで通してS3を使うための認証情報を取得する

動き的には、スクリーンショット 2020-08-29 16.11.59.png
1、Cognitoにログインして「アクセスキー・IDトークン」を取得する
2、IDトークンを使用してAWSを使用する認証情報を取得する
3、取得した認証情報でAWSサービスを使用する

Cognitoにログイン

main.php
<?php
  require_once 'vendor/autoload.php';
  use Cognito\cognitoClass;
  use Aws\CognitoIdentity\CognitoIdentityProvider;

  $cc = new cognitoClass();
  $username = 'example@email.com'; //Cognitoユーザーのメールアドレス
  $password = '123456'; //パスワード
  $config = require('config.php');
  
  list($access_token, $id_token) = $cc->login($username, $passwrod);
cognitoClass.php
<?php
  namespace Cognito;
  use pmill\AwsCognito\CognitoClient;
  use pmill\AwsCognito\Exception\ChallengeException;
  use pmill\AwsCognito\Exception\PasswordResetRequiredException;
  use Aws\Sdk;
  use Aws\CognitoIdentityProvider\CognitoIdentityProviderClient;

  class cognitoClass{
    protected $client;
    protected $config;

    public function  __construct(){
      $config = require(__DIR__ . '/../config.php');
      $config = $config['cognito'];
      $this->config = $config;
      $aws = new Sdk($config);
      $cognitoClient = $aws->createCognitoIdentityProvider();

      $client = new CognitoClient($cognitoClient);
      $client->setAppClientId($config['app_client_id']);
      $client->setAppClientSecret($config['app_client_secret']);
      $client->setRegion($config['region']);
      $client->setUserPoolId($config['user_pool_id']);
      $this->client = $client;
    }

    public function login($username, $password){
      $client = $this->client;
      $authenticationResponse = $client->authenticate($username,$password);

      if (isset($authenticationResponse['AuthenticationResult'])){
        $authenticationResponse = $authenticationResponse['AuthenticationResult'];
      }
      else if($authenticationResponse['ChallengeName'] == 'NEW_PASSWORD_REQUIRED'){
        $authenticationResponse = $client->respondToNewPasswordRequiredChallenge($username, $password, $authenticationResponse['Session']);
      }
      
      return [$authenticationResponse['AccessToken'], $authenticationResponse['IdToken']];
    }
  }
?>
config.php
<?php
return [
 'cognito' =>[
      'credentials' => [
        'key' => $_ENV['AWS_KEY'],
        'secret' => $_ENV['AWS_SECRET_KEY'],
      ],
      'region' => $_ENV['AWS_REGION'],
      'version' => 'latest',
      'app_client_id' => $_ENV['AWS_APP_CLIENT_ID'], //ユーザープールのアプリクライアントID
      'app_client_secret' => $_ENV['AWS_APP_CLIENT_SECRET'], //アプリクライアントIDのシークレット
      'user_pool_id' => $_ENV['AWS_USER_POOL_ID'], //ユーザープールのID
      'fed_pool_id' => $_ENV['AWS_FED_POOL_ID'],  //IDプールのID
    ] 
 ];

vendor/pmill/aws-cognitoのexampleフォルダに入っているコードを参考に独自クラス作り、login関数をつくりました。

Cognitoユーザのステータスを「FORCE_CHANGE_PASSWORD」から「CONFIRMED」にしないと、「アクセスキー・IDトークン」が返却されないようになっていますので、その変更する処理を加えています。
初期のままでも変更してくれようですが、上手く動いていなかったので手を加えています。。。

CognitClient.php
<?php
namespace pmill\AwsCognito;
...
class CognitoClient
{
...
    public function authenticate($username, $password)
    {
        try {
            $response = $this->client->adminInitiateAuth([
                'AuthFlow' => 'ADMIN_NO_SRP_AUTH',
                'AuthParameters' => [
                    'USERNAME' => $username,
                    'PASSWORD' => $password,
                    'SECRET_HASH' => $this->cognitoSecretHash($username),
                ],
                'ClientId' => $this->appClientId,
                'UserPoolId' => $this->userPoolId,
                ]);
            return $response;   
            #return $this->handleAuthenticateResponse($response->toArray());
        } catch (CognitoIdentityProviderException $e) {
            throw CognitoResponseException::createFromCognitoException($e);
        }
    }
...

main.phpを実行すると「アクセスキー・IDトークン」が帰ってきているかのを確認できるかと思います。

S3を使うための設定

CognitoユーザーがS3を使えるようにするには、フェデレーティッドアイデンティティの作成のさいに作成したIAMロールにポリシーをアタッチする必要があります。

スクリーンショット 2020-08-29 19.23.14.png
「〜Auth_Role」にポリシーをアタッチしましょう。

スクリーンショット 2020-08-31 10.20.03.png
ポリシーで扱うバケットを制限できるますが、今は「FullAccess」でいいでしょう。

S3にアップロード

main.php
<?php
  require_once 'vendor/autoload.php';
  use Cognito\cognitoClass;
  use Aws\CognitoIdentity\CognitoIdentityProvider;
  use Aws\S3\S3Client;
  use GuzzleHttp\Promise;

  $cc = new cognitoClass();
  $username = 'example@email.com'; //Cognitoユーザーのメールアドレス
  $password = '123456'; //パスワード
  $config = require('config.php');
  
  list($access_token, $id_token) = $cc->login($username, $passwrod);
  $ci = new CognitoIdentityProvider(
          $config['cognito']['fed_pool_id'],
          ['region'=>$config['cognito']['region'], 'version'=>'latest'],
          ['cognito-idp.'.$config['cognito']['region'].'.amazonaws.com/'.$config['cognito']['user_pool_id']=>$id_token]
          );
  $promise = $ci();
  $credentails = $promise->wait();

  $s3 = new S3Client(array(
    'version'=>'latest',
    'credentials'=>$credentails->toArray(),
    'region'=>'ap-northeast-1'
  ));

  $file = 'test.txt';
  $result = $s3->putObject([
    'Bucket'        => 'pool-example',
    'Key'           => 't.txt',
    'SourceFile'    => $file,
    'ContentType'   => mime_content_type($file),
  ]);

CognitoIdentityProviderにCognitoの情報を引数に渡したら、promise関数で帰ってくるのでそれに対応した取得の仕方をすると認証情報を取得できます。

main.php
list($access_token, $id_token) = $cc->login($username, $passwrod);
  $ci = new CognitoIdentityProvider(
          $config['cognito']['fed_pool_id'],
          ['region'=>$config['cognito']['region'], 'version'=>'latest'],
          ['cognito-idp.'.$config['cognito']['region'].'.amazonaws.com/'.$config['cognito']['user_pool_id']=>$id_token]
          );

CognitoIdentityProviderには第1引数にIDプールのID、第2引数にIDプールのリージョン・バージョン、第3引数にログイン方法を渡します。

このまま、mainを実行するとs3にtest.txtがアップロードされていることが確認できると思います。
スクリーンショット 2020-08-31 12.12.52.png

さいごに

最後まで見ていただきありがとうございます。
今回はCognitoを通してに認証でしたが、他にもAmazon・Facebook・Apple・Twitterなどがあります。

2
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?