背景
AWS使ってサーバーレスで自分用の家計簿的なwebサービスを勉強も兼ねて開発中。
2つ前の記事
1つ前の記事
せっかくCognito使ったので、ユーザー毎のS3フォルダにアクセスする事をしてみたい。
構成
フロント:Vue.js + Element.ui
サーバーサイド:CloudFront + S3 + APIGateway + Lambda + DynamoDB + Cognito
やってみた
今回、様々なページを参考にさせてもらい、その情報を組み合わせました。もはやどの部分がどのページの参考なのかこんがらがっています。結構トライ&エラー発生し、各種設定行ったり戻ったりしました。今回は結果のみ共有させてもらいます。
まず、ブラウザからS3にアクセスする為、CORSの設定をします。
<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
<AllowedOrigin>*</AllowedOrigin>
<AllowedMethod>GET</AllowedMethod>
<AllowedMethod>PUT</AllowedMethod>
<MaxAgeSeconds>3000</MaxAgeSeconds>
<AllowedHeader>Authorization</AllowedHeader>
<AllowedHeader>Content-*</AllowedHeader>
<AllowedHeader>Host</AllowedHeader>
<AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
ログインユーザー毎にS3へのアクセスを許可する為、CognitoIDプール、認証済みユーザー用のIAMポリシーに以下設定。※以下の指定でhogehoge-bucketと指定していますが既に存在するようです。が、そのバケットを意味してないです。実際には自分作成のバケット名です。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": [
"cognito-identity:*",
"mobileanalytics:PutEvents",
"cognito-sync:*"
],
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:GetObject",
"s3:ListBucket",
"s3:DeleteObject",
"s3:GetBucketLocation"
],
"Resource": [
"arn:aws:s3:::hogehoge-bucket/cognito/myhome-account/${cognito-identity.amazonaws.com:sub}",
"arn:aws:s3:::hogehoge-bucket/cognito/myhome-account/${cognito-identity.amazonaws.com:sub}/*"
]
}
]
}
そして処理本体、VueファイルのjavaScript部分。※ログイン処理が済んでいる事が前提です。ログイン部分は2つ前の記事を参照してみて下さい。
import AWS from 'aws-sdk'
import awsconfig from '../cognito/config'
import cognito from '@/cognito'
const S3_USERBACKETNAME = 'hogehoge-bucket'
const PROVIDER_KEY = 'cognito-idp.' + awsconfig.Region + '.amazonaws.com/' + awsconfig.UserPoolId
/* ・・中略・・ */
s3test: function () {
const cognitoUser = this.$cognito.userPool.getCurrentUser()
cognitoUser.getSession((err, session) => {
if (!err && session.isValid()) {
const itoken = session.getIdToken().getJwtToken()
// Initialize the Amazon Cognito credentials provider
AWS.config.region = awsconfig.Region
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: awsconfig.IdentityPoolId,
Logins: {
[PROVIDER_KEY]: itoken
}
})
var identityId = AWS.config.credentials.identityId
var s3key = 'cognito/myhome-account/' + identityId + '/testfile.txt'
// refresh AWS credentials
AWS.config.credentials.refresh((err) => {
if (err) {
console.log(err)
} else {
var s3 = new AWS.S3({
params: { Bucket: S3_USERBACKETNAME }
})
const updateParams = {
Key: s3key,
Body: 'teststring',
ContentType: 'application/text'
}
s3.upload(updateParams, function (err, data) {
if (err) {
console.log('error : ', err)
} else {
console.log('success : ' + S3_USERBACKETNAME + '/' + s3key)
}
})
}
})
}
})
}
これでテスト用の適当な文字列のファイルをS3のユーザー毎フォルダにアップ出来ました。間違ったフォルダを指定した時は AccessDenied: Access Denied で失敗する事も確認できました。
特にはまったポイント
- credentialを取得する時に、一時トークンを渡すが、認証プロバイダーとしてcognitoユーザープールを使う場合にどんなキー(上記ソースのPROVIDER_KEY部分)を指定するのか情報を見つけるのに非常に時間がかかった。参考
- ポリシーで指定するcognito-identity.amazonaws.com:subが実際には何の値を示すのか見つけるのに非常に時間がかかった。参考
参考にさせてもらったページ
ブラウザから Amazon S3 への写真のアップロード
サインイン後に ID プールを使用して AWS サービスへアクセスする
[ Serverless ] Cognito、S3、Lambdaで認証機能付きのWebサイトを作ってみました
【Cognito】Amazon Cognito Identity SDK for JavaScriptで動くサンプルを作ってみた #2/2【JavaScript】
WebブラウザからAmazon S3に直接ファイルをアップロードする
AWS Cognitoを使ってサーバレスアプリケーションに認証をつける