share facebook facebook twitter menu hatena pocket slack

2017.02.20 MON

Amazon S3 + Cognito で簡易アンケートシステムを作る写経(Amazon S3 で HTML フォームを実装する写経)

川原 洋平

WRITTEN BY 川原 洋平

やりたいこと

  • S3 で構成されたサイトに HTML フォームを実装し、アンケートページ的なものを提供したい
  • 最終的には S3 の前には CloudFront を挟む予定
  • 投稿の内容は S3 に JSON で保存する

図にすると以下のような感じ。

参考

S3 + Lambda + Cognitoを使って、簡単お問い合わせシステム構築 - Qiita
S3とLambdaとCognitoを使って、簡単でセキュアなお問い合わせフォームシステムを作ってみます。**Cognitoがバージニア/アイルランドのみ利用可能ですので、今回はS3/Lambda/Congito全部バージニア(us...

qiita.com

ありがとうございます。ほぼ、上記ページの写経となります。

ピュアな JavaScript でフォーム(form)系要素の値を取得, 設定する方法一覧
先日書いた 『サーバーだけに頼る時代は終わった!? クライアントサイドでしっかり Validation する方法 | phiary』 がありがたいことに好評だったので今回も form について書こうと思います. はじめに 『form 値 取得』とかで検索すると for 文で一通りチェックして....

phiary.me

HTML フォームを JavaScript から扱う方法は上記のページが参考になりました。有難うございます。

検証環境

OS

$ sw_vers
ProductName:    Mac OS X
ProductVersion: 10.11.6
BuildVersion:   15G1217

AWS CLI

$ aws --version
aws-cli/1.11.19 Python/2.7.10 Darwin/15.6.0 botocore/1.4.76

Data Bucket に未認証ユーザーが書き込めるような環境を AWS CLI で用意する

Cognito や IAM 等を色々と設定する必要があるけど、AWS CLI で全部準備する。

#
# 各環境変数に値を定義
#
_PROFILE=washino-profile
_REGION=ap-northeast-1
_DOMAIN_NAME=washi.inokara.tech
_IDENTITY_POOL_NAME=washino_identity
_S3_BUCKET_NAME=data-bucket

#
# identity pool を作成
#
_IDENTITY_POOL_ID=$(aws --profile ${_PROFILE} cognito-identity create-identity-pool --identity-pool-name ${_IDENTITY_POOL_NAME} --allow-unauthenticated-identities --query IdentityPoolId --output text)
echo ${_IDENTITY_POOL_ID}

#
# S3 バケットを作成
#
aws --profile ${_PROFILE} --region ${_REGION} s3 mb s3://${_S3_BUCKET_NAME}

#
# 作成したバケットに CORS を設定(これをやっとかんといかんばい)
#
cat << EOT >> cors.json
{
  "CORSRules": [
    {
      "AllowedOrigins": ["https://${_DOMAIN_NAME}"],
      "AllowedHeaders": ["*"],
      "AllowedMethods": ["PUT"]
    }
  ]
}
EOT
aws --profile ${_PROFILE} s3api put-bucket-cors --bucket ${_S3_BUCKET_NAME} --cors-configuration file://cors.json

#
# バケットポリシーを作成
#
cat << EOT >> s3PutAllowPolicy.json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "S3PutAllowPolicy",
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl"
            ],
            "Resource": "arn:aws:s3:::${_S3_BUCKET_NAME}/*"
        }
    ]
}
EOT
_POLICY_ARN=$(aws --profile ${_PROFILE} iam create-policy --policy-name s3PutAllowPolicy --policy-document file://s3PutAllowPolicy.json --query Policy.Arn --output text)
echo ${_POLICY_ARN}

#
# identity pool に付与する IAM Role を作成
#
cat << EOT >> ${_IDENTITY_POOL_NAME}_authenticated.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": ${_IDENTITY_POOL_ID}
        },
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "authenticated"
        }
      }
    }
  ]
}
EOT
_IAM_ROLE_ARN=$(aws --profile ${_PROFILE} iam create-role --role-name cognito_${_IDENTITY_POOL_NAME}_authenticated --assume-role-policy-document file://${_IDENTITY_POOL_NAME}_authenticated.json --query Role.Arn --output text)
aws --profile ${_PROFILE} iam attach-role-policy --role-name cognito_${_IDENTITY_POOL_NAME}_authenticated --policy-arn ${_POLICY_ARN}

#
# identity pool に IAM Role を適用する
#
aws --profile ${_PROFILE} cognito-identity set-identity-pool-roles --identity-pool-id ${_IDENTITY_POOL_ID} --roles authenticated=${_IAM_ROLE_ARN}

#
# identity pool に付与する IAM Role を作成(未認証ユーザー用)
#
cat << EOT >> ${_IDENTITY_POOL_NAME}_unauthenticated.json
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "Federated": "cognito-identity.amazonaws.com"
      },
      "Action": "sts:AssumeRoleWithWebIdentity",
      "Condition": {
        "StringEquals": {
          "cognito-identity.amazonaws.com:aud": ${_IDENTITY_POOL_ID}
        },
        "ForAnyValue:StringLike": {
          "cognito-identity.amazonaws.com:amr": "unauthenticated"
        }
      }
    }
  ]
}
EOT
_IAM_ROLE_ARN=$(aws --profile ${_PROFILE} iam create-role --role-name cognito_${_IDENTITY_POOL_NAME}_unauthenticated --assume-role-policy-document file://${_IDENTITY_POOL_NAME}_unauthenticated.json --query Role.Arn --output text)
aws --profile ${_PROFILE} iam attach-role-policy --role-name cognito_${_IDENTITY_POOL_NAME}_unauthenticated --policy-arn ${_POLICY_ARN}

#
# identity pool に IAM Role を適用する
#
aws --profile ${_PROFILE} cognito-identity set-identity-pool-roles --identity-pool-id ${_IDENTITY_POOL_ID} --roles unauthenticated=${_IAM_ROLE_ARN}

#
# 後片付け(やらなくても良い)
#
rm -f cors.json s3PutAllowPolicy.json ${_IDENTITY_POOL_NAME}_authenticated.json ${_IDENTITY_POOL_NAME}_unauthenticated.json

あとは HTML と JavaScript でフォームを用意して HTML Bucket に放り込む

HTML はこんな感じ




    
    
    
    雑なアンケート


     
お名前
メールアドレス
性別 未選択
世の中に不満を 感じる 感じない 未選択
2017 年ホークスは 優勝する 優勝しない 未選択
コメントをどうぞ
>

JavaScript はこんな感じ

//
// demo.js
//
var $aws_region = "ap-northeast-1";
var $aws_cognito_identity_pool_id = "ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxxxx"; // Cognito で作成した identity pool id を設定する
var $s3_prefix = "data/201702/";
var $s3_bucket = "xxxxxxxxxxxxxxxxxxxxxxxx";

AWS.config.region = $aws_region;
AWS.config.credentials = new AWS.CognitoIdentityCredentials({IdentityPoolId: $aws_cognito_identity_pool_id});
// AWS.config.credentials.get(function(err) {
//     if (!err) {
//         console.log("Cognito Identify Id: " + AWS.config.credentials.identityId);
//     }
// });

function postMessage() {
    var form = document.forms.orenoForm;
    var now = new Date();
    var obj = {"name": form._name.value,
               "mail": form._mail.value,
               "comment": form._comment.value,
               "sex": form._sex.value,
               "fuman": form._fuman.value,
               "hawks": form._hawks.value,
               "date": now.toLocaleString()};
    var s3 = new AWS.S3({params: {Bucket: $s3_bucket}});
    var blob = new Blob([JSON.stringify(obj, null, 2)], {type:'text/plain'});
    s3.putObject({Key: $s3_prefix + now.getTime() +".json", ContentType: "text/plain", Body: blob, ACL: "public-read"},
    function(err, data){
        if(data !== null){
            location.href="thanks.html";
        }
        else{
            alert("Post Failed: " + err.message);
        }
    });
}

Chrome で見ると…

なんかアンケートページっぽいですな。

アンケートに答えると…

以下のように S3 バケットに JSON データが保存される。

bash-3.2$ ls -tr *.json
1486298468151.json      1486298522074.json      1486298702117.json
bash-3.2$ cat 1486298702117.json | jq .
{
  "date": "2017/2/5 21:45:02",
  "hawks": "優勝する",
  "fuman": "感じない",
  "sex": "女",
  "comment": "ああああ",
  "mail": "hanako@example.com",
  "name": "やまだはなこ"
}

集計とか

S3 の put イベントを拾って Lambda と組み合わせる例が紹介されているけど、とりあえずは Google SpreadSheet に結果を突っ込んでおけば良さそうということで、以下の記事のように Google SpreadSheet に突っ込んでおくことにする。

Python で JSON データを Google SpreadSheet に突っ込むメモ - ようへいの日々精進XP
以下のような JSON 情報が記録されたオブジェクトがある 以下のようなスクリプトを書いて突っ込む 実行 メモ Google Drive API の認証設定 gspread gspread でデータを挿入 以上 後は… メモでした 以下のような JSON 情報が記録されたオブジェクトがある { "nam...

inokara.hateblo.jp

Elasticsearch とかに突っ込んでも面白そうだけど。

以上

メモでした。

元記事はこちら

Amazon S3 + Cognito で簡易アンケートシステムを作る写経(Amazon S3 で HTML フォームを実装する写経)

cloudpack

cloudpackは、Amazon EC2やAmazon S3をはじめとするAWSの各種プロダクトを利用する際の、導入・設計から運用保守を含んだフルマネージドのサービスを提供し、バックアップや24時間365日の監視/障害対応、技術的な問い合わせに対するサポートなどを行っております。
AWS上のインフラ構築およびAWSを活用したシステム開発など、案件のご相談はcloudpack.jpよりご連絡ください。