#実現したいこと
APIGatewayで認証を"AWS_IAM"に設定したAPIをブラウザからJavascriptで叩きます。これにより、CognitoのUnauthUserとAuthUserでアクセスできるAPIを制御することができます。
#やること
分かりやすいように順を追ってやっていきます。
- Lambdaで簡単なFunctionを作成
- APIGatewayで上記Functionを呼び出すAPIを作成する
- 作成したAPIのCORSを有効化する
- APIをデプロイし、API用のJavascript SDKを作成し、ダウンロードする
- 認証なしでAPIを叩くJavascriptのコードを書く(ここで一度テストし、うまくいくことを確認)
- APIの認証を"なし"→"AWS_IAM"に設定する(ここで一度テストし、アクセスが拒否されることを確認)
- Cognito Identity Poolを作成
- APIの実行を許可するIAMを作成し、UnauthUserのRoleにアタッチする
- Cognito UnauthUserのCredentialでAPIを叩くJavascriptのコードを書く(完成)
##Lambdaで簡単なFunctionを作成
「Lambda」で"Create Function"> 「Select BluePrint」で"Blank Function"を選択>「Configure triggers」はそのままで"Next"
この画面では、関数の中身は編集しません。"FunctionName"に適当な関数名(myHelloWorldFuncなど)をつけ、下記の"Lambda function handler and role"のところで"Create a custom role"を選択します。
すると別タブでIAMが開くので、"新しいIAMロールの作成"を選択して、そのまま右下の"許可"をクリックします。(すると、「lambda_basic_execution」という必要最低限のRoleが生成され、作成中のLambda Functionに適用されます。)
Functionの設定画面に戻ったら、"Lambda function handler and role"にさきほどの「lambda_basic_execution」が適用されていることを確認し、右下のOKをクリックします。
これで、実行すると「Hello World」とだけ返してくるLambda関数が完成しました。
##APIGatewayで上記Functionを呼び出すAPIを作成する
「APIGateway」で"APIを作成"
"アクション">"リソースの作成"
"アクション" > "メソッドの作成"
ここでGetメソッドを作成します。(チェックマークをクリックして確定するのを忘れずに)
セットアップの画面では、Lambda関数を選択し、さきほど作ったmyHelloWorldFunctionのリージョンを選択して、myHelloWorldFunctionを設定し、"保存"をクリックします。
Getメソッドが作成できました。
##作成したAPIのCORSを有効化する
"アクション" > "CORSの有効化"をクリック
メソッドのGETにチェックが入っていることを確認し、それ以外の設定はいじらずに"CORSを有効にして既存のCORSヘッダーを置き換え"をクリック
CORSが有効化され、GETメソッドの下にOPTIONメソッドが追加されていればOKです。
##APIをデプロイし、API用のJavascript SDKを作成し、ダウンロードする
testリソースが選択された状態で、"アクション" > "APIのデプロイ"をクリック
ここでは「dev」という名前の新しいステージを作成し、デプロイします。
「ステージエディター」で"SDKの生成"から、プラットフォーム"Javascript"を選択し、SDKの生成をクリックします。
すると、SDKのファイルがダウンロードできます。
##認証なしでAPIを叩くJavascriptのコードを書く(ここで一度テストし、うまくいくことを確認)
SDKのZIPを解答したら、中に適当なHTMLファイルを作成し、下記のコードを書きます。(ここではAPIGatewayTest.htmlというファイルを作成しています。)
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>API test</title>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- API用SDK -->
<script type="text/javascript" src="lib/axios/dist/axios.standalone.js"></script>
<script type="text/javascript" src="lib/CryptoJS/rollups/hmac-sha256.js"></script>
<script type="text/javascript" src="lib/CryptoJS/rollups/sha256.js"></script>
<script type="text/javascript" src="lib/CryptoJS/components/hmac.js"></script>
<script type="text/javascript" src="lib/CryptoJS/components/enc-base64.js"></script>
<script type="text/javascript" src="lib/url-template/url-template.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/sigV4Client.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/apiGatewayClient.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/simpleHttpClient.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/utils.js"></script>
<script type="text/javascript" src="apigClient.js"></script>
</head>
<body>
<!-- HTML -->
<button id="btn">ボタン</button>
<!-- Other Script -->
<script type="text/javascript">
var apigClient;
$(function(){
//API Clientを初期化
apigClient = apigClientFactory.newClient();
});
$('#btn').click(function(){
//testリソースのGetメソッドを呼び出すので、.testGet()
apigClient.testGet({}, {}, {})
.then(function(result){
// Add success callback code here.
console.log(result);
}).catch( function(result){
// Add error callback code here.
console.log(result);
});
});
</script>
</body>
</html>
ボタンをクリックすると、APIの呼び出しが成功し、Lambdaから'HelloWorld'の文字列が返ってくることを確認します。
##APIの認証を"なし"→"AWS_IAM"に設定する(ここで一度テストし、アクセスが拒否されることを確認)
ここで、作成したAPIの"メソッドリクエスト"に記載されている**ARN(Amazon Resource Name)**をコピーしておきます。("arn:aws:execute-api:ap-notheast-xxxxxxxx/*/GET/test"という文字列です。)
作成したAPIのGetメソッドの"メソッドリクエスト"をクリック
こうして再びボタンを押してAPIを叩いてみると、403エラーが返ってくることを確認します。認証をAWS_IAMに設定したため、アクセスが拒否されています。(CORSに問題があるというエラー文ですが、問題ありません。)
##Cognito Identity Poolを作成
「Cognito」で"Manage Federated Identities"をクリック > "Create Identity Pool"をクリック
次の画面では、Identity Poolの名前(ここでは"MyTestIdentity")を入力し、"Enable access to unauthenticated identities"にチェックを入れた上で"Create Pool"をクリックします。
次の画面で確認できる**"Identity Pool ID"**をコピーしておきます。
##APIの実行を許可するIAMを作成し、UnauthUserのRoleにアタッチする
「IAM」で"ロール"を開くと、さきほど"MyTestIdentity"というIdentity Poolを作成した時にCognito_MyTestIndentityUnauth_Roleという未認証ユーザー用のRoleと、Cognito_MyTestIndentityAuth_Roleという認証済みユーザー用のRoleが2つ作成されているのが確認できます。今回はCognitoの未認証ユーザーに対してAPIへのアクセス権限を与えるので、"Cognito_MyTestIndentity Unauth _Role"をクリックします。
"Policy Generator"にチェックを入れ、"選択"をクリックします。
「アクセス許可の編集」では、下記のように設定します。
- 効果:許可
- AWSサービス:Amazon APIGateway
- アクション:Invoke
- Amazonリソースネーム(ARN):先ほどコピーしたGETメソッドのARN
これらを設定し、"ステートメントを追加"をクリックします。
下記のようになっていれば、OKです。"次のステップ"をクリックします。
次の確認画面では何もせず、"ポリシーの適用"をクリックします。
これで、UnauthUserに対してAPIを実行する許可を与えることができます。
##Cognito UnauthUserのCredentialでAPIを叩くJavascriptのコードを書く(完成)
さきほど作成したHTMLファイルを、下記のように編集します。
-
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.19.min.js"></script>
でAWS SDK for Javascriptを読み込み -
AWS.config.credential
のパラメーターにさきほどコピーしたIdentity Pool IDを貼り付ける -
AWS.config.credential.get()
によって得られるaccessKeyIdとsecretAccessKeyとsessionToken、及びregionをapigClientに設定して初期化する。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<title>API test</title>
<!-- AWS SDK -->
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.19.min.js"></script>
<!-- jQuery -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- API用SDK -->
<script type="text/javascript" src="lib/axios/dist/axios.standalone.js"></script>
<script type="text/javascript" src="lib/CryptoJS/rollups/hmac-sha256.js"></script>
<script type="text/javascript" src="lib/CryptoJS/rollups/sha256.js"></script>
<script type="text/javascript" src="lib/CryptoJS/components/hmac.js"></script>
<script type="text/javascript" src="lib/CryptoJS/components/enc-base64.js"></script>
<script type="text/javascript" src="lib/url-template/url-template.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/sigV4Client.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/apiGatewayClient.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/simpleHttpClient.js"></script>
<script type="text/javascript" src="lib/apiGatewayCore/utils.js"></script>
<script type="text/javascript" src="apigClient.js"></script>
</head>
<body>
<!-- HTML -->
<button id="btn">ボタン</button>
<!-- Other Script -->
<script type="text/javascript">
var apigClient;
$(function(){
//AWS Credentialの初期化
AWS.config.region = 'ap-northeast-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
IdentityPoolId: 'ap-northeast-XXXXXXXXXXXXXXXXXXXXXXX' //Identity Pool Idを貼り付ける(ARNではない。)
});
AWS.config.credentials.get(function(err){
if(!err){
//API ClientにaccessKey,secretKey,sessionToken,regionを設定し、初期化します。
apigClient = apigClientFactory.newClient({
accessKey: AWS.config.credentials.accessKeyId,
secretKey: AWS.config.credentials.secretAccessKey,
sessionToken: AWS.config.credentials.sessionToken,//大事
region: 'ap-northeast-1'//大事
});
}else{
console.log(err);
}
});
});
$('#btn').click(function(){
apigClient.testGet({}, {}, {})
.then(function(result){
// Add success callback code here.
console.log(result);
}).catch( function(result){
// Add error callback code here.
console.log(result);
});
});
</script>
</body>
</html>
これでボタンをクリックすると、APIの呼び出しに成功し、Lambdaから'Hello World'の文字列が返ってくることを確認できます。
#ポイント
- CORSを有効化したり認証を変更したりなど、APIの設定をいじった後は、APIをデプロイするのを忘れない。
- APIGatewayで生成したJavascript用のSDKは、超絶面倒くさいSignature V4の署名付きリクエストをやってくれる。
- apigClientにアクセスキーとシークレットキーを設定する時、sessionTokenとregionはドキュメントではオプションとなっているが、ここを設定しないと動かないので全て設定する。(ここでだいぶハマった。)
##参考URL
API Gateway リソースの CORS を有効にする
API 実行アクセス権限の IAM ポリシーの例
API Gateway コンソールを使用して API の SDK を生成する
API Gateway で生成した JavaScript SDK を使用する
aws-api-gateway-client