[AWS] API Gateway で Authorization AWS_IAM のときに JavaScript SDKからアクセスする

2018/10/18

こんにちは。きんくまです。

サーバーレスについて調べていました。
それで、API Gateway から Lambda につないでメッセージを返すチュートリアルをやってまして。認証つきになった場合にうまくいかなくて詰まったときのメモです。作業メモなのであんまし役にたたないかも。

このページのチュートリアルを順番に進めていました。
>> Getting Started with Amazon API Gateway

で、今回のやつはこれです。
>>Build an API Gateway API with Custom Lambda Integration

Authorization NONEのとき

順調にすすめてまして、ページの最後にある curl を使ったテストもうまくいきました。

ローカルに作ったテストページからJSでアクセスするのもうまくいきました。
こんな感じです。ここでは特にAWSのSDKは使っていません。axiosライブラリのみ読み込んでいます。

let api = 'https://XXXXXX.execute-api.ap-northeast-1.amazonaws.com/test/';
let url = api + 'Seattle';

axios({
    url: url,
    method:'POST',
    headers: {
        day:"Thursday",
    },
    params:{
        time:'evening'
    },
    data:{
        callerName:"John"
    }
}).then(function(res){
    console.log('success');
    console.log(res);
    console.log(res.data);
}).catch(function(error){
    console.log('error-')
    console.error(error);
});

1点 CORSの設定をする必要がありました。

>> Enable CORS for an API Gateway Resource

このとき、デフォルトで入る Access-Control-Allow-Headers の値
‘Content-Type,X-Amz-Date,Authorization,X-Api-Key,X-Amz-Security-Token’
に続けて ‘,day,x-amz-docs-region’ というのを追加で設定しておきました。

Authorization AWS_IAM

ここから本番です。認証つきになったときです。これが公式ドキュメントを読んでやってみるもののどうしてもうまくいかない!

API GatewayのJavaScript SDKのページ
>> Use a JavaScript SDK Generated by API Gateway

あとこれをみてました。
>> Control Access for Invoking an API

まず、IAMで AmazonAPIGatewayInvokeFullAccessポリシーをつけたユーザーを作りました。で accessKeyと secretKeyをメモして、上のSDKのチュートリアルのところにあてはめてみたのですが、クロスドメインエラーが出る。

var apigClient = apigClientFactory.newClient({
  accessKey: 'ACCESS_KEY',
  secretKey: 'SECRET_KEY',
});

結論からいいますと、上の公式ページの情報だけでは足りませんでした。というかやり方が間違ってました。
IAMでUserを作る方法はうまくいかなかったです。Cognitoの Identity Poolを利用したらうまくいきました。

詳しいやり方はググったところ、こちらのページでわかりました。すばらしい!

>> APIGatewayのIAM認証付きのAPIをJavascriptから叩く

つまったところのメモとしては

1. AuthorizationをAWS_IAMにするのは、OPTIONSじゃなくて、GETやPOSTなどの方だけにつける
2. API GatewayでgenerateされたSDKだけじゃなくて aws-sdk も追加で必要
3. IAMでUserを作るのではなくて Cognito の Identity Pool を作る
4. 認証には AWS.config.credentials を利用する
5. クロスドメインエラー(Access-Control-Allow-Originがないとかいうやつ)は本当にCORSの設定をしていないこともあるが、認証がうまくいっていなくてもそのエラーになるので注意する(ここでハマるw)

Cognitoの認証をJSのSDKからやるのはここにドキュメントがありました。

>> Getting Credentials

実際のコードです。
html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<!--aws-sdkを追加-->
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.19.min.js"></script>
<!--apigatewayから吐き出された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>
<!--自作-->
<script src="using-apigateway-sdk-sample.js"></script>
</body>
</html>

using-apigateway-sdk-sample.js

AWS.config.region = 'ap-northeast-1';
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
    IdentityPoolId: 'ap-northeast-1:XXXXXXXXX',
});
AWS.config.credentials.get(function(err) {
    //この中ではcredentialsのsessionTokenなどの情報がちゃんと取得されてマス
    var apigClient = apigClientFactory.newClient({
        accessKey: AWS.config.credentials.accessKeyId,
        secretKey: AWS.config.credentials.secretAccessKey,
        sessionToken: AWS.config.credentials.sessionToken,
        region: AWS.config.region
    });
    testPost(apigClient);
});


function testPost(apigClient){
    var params = {
        day:"Thursday",
        time:'evening',
        city:'Seattle'
    };

    var body = {
        callerName:"John"
    };

    var additionalParams = {
        headers: {

        },
        queryParams: {

        }
    };

    apigClient.cityPost(params, body, additionalParams)
        .then(function(result){
            console.log('success', result);
        }).catch( function(result){
            console.error(result);
    });
}

実際にリクエストをなげているところを見てもらうと、認証なしのときと比べて、認証つきでsdkを使うときはパラメーターの渡し方がちょっと違ってます。
SDKを利用しない場合は headerやparams のところに入れたりします。
ですが、sdkのときは additionalParamsの中の headersとかqueryParamsの中ではなくて、ConsoleでMapping Templatesしたパラメータを全てparamsの中に入れる必要がありました。

今回はこんな感じのメモでしたー。

LINEで送る
Pocket

自作iPhoneアプリ 好評発売中!
フォルメモ - シンプルなフォルダつきメモ帳
ジッピー電卓 - 消費税や割引もサクサク計算!

LINEスタンプ作りました!
毎日使える。とぼけたウサギ。LINEスタンプ販売中! 毎日使える。とぼけたウサギ

ページトップへ戻る