更新(2017/11/18)
- S3にあげるたびに更新が起こるのを阻止
- HTML5のvalidationを使う
- アップロードが完了した場合内容を画面上部に表示
やりたいこと
- S3上にHTMLとJSファイルをおいて静的webページとして公開
- webページに入力した内容をcsvにまとめてS3に出力
- 認証はgoogleのOpenID Connectを使用(roleをつけておく)
- バケットポリシーでIP制限をかけておく
S3でwebページ公開に関して
以下のサイトを参考にして公開
S3で静的ウェブサイトをホスティングしてみる
バケットポリシーも作っておく
googleのOpen Connect周り
以下のサイトを参考にクライアントID+認証周り作成
Googleの「OpenID Connect」を利用する為の「クライアントID」の取得方法
Googleと連携するroleの作成
AWSのコンソール画面で
IAM > role > roleの作成
と進み、ウェブIDのタブを選択してプロバイダーにGoogleを選択
AudienceにはクライアントIDを入力してpolicyのattachなどを行う
例で用いたpolicyはS3の特定のフォルダにのみアクセス可能なものにしました
policy.json
{
"Version": "2012-10-17",
"Statement": [
{
"Action": [
"s3:PutObject",
"s3:PutObjectAcl"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME/output/*"
],
"Effect": "Allow"
},
{
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::BUCKET_NAME"
],
"Effect": "Allow",
"Condition": {
"StringEquals": {
"s3:prefix": "output"
}
}
}
]
}
いよいよJavascript作成
フォルダ構成
- BUCKET
- output
- HTML
- index.html
- favicon.ico
- logic.js
ログイン周り
以下のURLを参考にJavascriptを作成(ログイン箇所に関しては例をそのまま使用)
ブラウザの JavaScript
Web Federated Identity Examples
index.html
<!DOCTYPE html>
<html>
<head>
<link rel="shortcut icon" type="image/x-icon" href="favicon.ico">
<title>AWS SDK for JavaScript - Sample Application</title>
<meta charset="utf-8"/>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet">
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.1.12.min.js"></script>
</head>
<body>
<div id="results" role="alert"></div>
<nav class="navbar navbar-default">
<div class="container">
<!-- 2.ヘッダ情報 -->
<div class="navbar-header">
<a class="navbar-brand">S3アップローダー</a>
</div>
</div>
</nav>
<div class="container" id="form">
<form>
<div class="form-group" id="name">
<label>名前</label>
<input type="text" name="name" class="form-control" placeholder="申請 太郎" required>
</div>
<div class="form-group" id="account_flg">
<label>アカウント</label>
<select name="account_flg" class="form-control">
<option value="不要">不要</option>
<option value="必要">必要</option>
</select>
</div>
...
<button type="button" onclick="upload_csv();" class="btn btn-primary">申請登録</button>
</form>
</div>
<span
id="login"
class="g-signin"
data-height="short"
data-callback="loginToGoogle"
data-cookiepolicy="single_host_origin"
data-requestvisibleactions="http://schemas.google.com/AddActivity"
data-scope="https://www.googleapis.com/auth/plus.login">
</span>
<script>
//以下ほぼサンプルのコピペ
//s3 = null; s3をアップローダーでも使いたいので後々グローバル変数で指定しています
var clientID = '************.apps.googleusercontent.com'; // Google client ID
var roleArn = 'arn:aws:iam::************:role/ROLE_NAME';
document.getElementById('login').setAttribute('data-clientid', clientID);
function loginToGoogle(response) {
if (!response.error) {
AWS.config.credentials = new AWS.WebIdentityCredentials({
RoleArn: roleArn,
WebIdentityToken: response.id_token
});
s3 = new AWS.S3();
console.log('You are now logged in.');
} else {
console.log('There was a problem logging you in.');
}
}
(function () {
var po = document.createElement('script');
po.type = 'text/javascript';
po.async = true;
po.src = 'https://apis.google.com/js/client:plusone.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(po, s);
})();
</script>
<script src="logic.js"></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
</body>
</html>
アップローダー周り
logic.js
//ここに必要な項目のIDを書いておく
csv_array = [
'name',
'account_flg'
]
//メインのところ(どのcsvを作成するか)
function upload_csv() {
//連続で投稿する場合に結果画面を一度空欄にする
document.getElementById('results').innerHTML = "";
//inputタグを指定してvalidation確認
var validity_list = document.getElementById("form").getElementsByTagName("div");
for (var i = 0, l = validity_list.length; i < l; i++) {
var validity_zone = validity_list[i].getElementsByTagName("input")[0];
if (!validity_zone) {
continue;
}
if (!validity_zone.checkValidity()) {
alert('【'+validity_list[i].getElementsByTagName("label")[0].innerHTML + '】 '+ validity_zone.validationMessage);
return;
}
}
//成功・失敗検知用
success_flg = true;
upload('account', make_csv(csv_array));
//終わった後上部に移動して結果をalertで通知
$("html,body").animate({scrollTop: 0}, 'fast');
if (success_flg) {
alert('Success upload');
} else {
alert("Fail upload ...");
}
//画面更新を防ぐ
return false;
}
//配列情報から変数(csv)にヘッダー情報と内容を入れる関数
function make_csv(array) {
var csv = '';
for (i in array) {
var block = document.getElementById(array[i]);
csv += block.getElementsByTagName("label")[0].innerHTML + ',';
}
csv = csv.slice(0,-1);
csv += '\n';
for (i in array) {
var block = document.getElementById(array[i]);
if (block.getElementsByTagName("select")[0]){
var num = block.getElementsByTagName("select")[0].selectedIndex;
csv += block.getElementsByTagName("select")[0].options[num].value + ',';
} else {
csv += block.getElementsByTagName("input")[0].value + ',';
}
}
csv = csv.slice(0,-1);
return csv;
}
//出来上がったcsvファイルをアップロードする関数
function upload(service_name, body) {
var results = document.getElementById('results');
var params = {
Bucket: 'BUCKET_NAME',
Key: 'output/' + service_name + '_' + timestamp() + '.csv', //名前が被らないようにtimestam付
ContentType: 'csv',
Body: body
};
s3.putObject(params, function (err, data) {
if (err) {
success_flg = false;
}
//実行結果を画面上部に表示
results.setAttribute("class", !err ? 'alert alert-success':'alert alert-danger' );
if (!err){
results.innerHTML = results.innerHTML + "<strong>【"+service_name+"】</strong>";
}else{
results.innerHTML = results.innerHTML + "<strong>ERROR【"+service_name+"】</strong>";
}
});
}
//タイムスタンプ作成用関数
function timestamp() {
var d = new Date();
var year = d.getFullYear();
var month = d.getMonth() + 1;
var day = d.getDate();
var hour = ( d.getHours() < 10 ) ? '0' + d.getHours() : d.getHours();
var min = ( d.getMinutes() < 10 ) ? '0' + d.getMinutes() : d.getMinutes();
return '' + year + month + day + hour + min;
}
終わりに
IP制限をかけておけば簡単に社内サービスを作成できます
単にローカルファイルを上げるだけであれば、htnl上でファイル取得をしてuploadの関数を使えばできます
サーバーレス素晴らしい