サーバレスAPI認証作成手順

こんにちは。すーさんです。

今回はAWSで簡易的な認証システムの作り方を説明します。
(※入金の確認や認証キーの送付は考慮していないちょー簡易的なものなので、完全自動化する場合は別途組み込む必要があります。)

ちなみに、入金システムは利用料金的にもセキュリティ的にもPAY.JPがオススメです。(クレジットカード決済、ApplePayに対応しています。)

Step1 DynamoDBでテーブルの定義をする

テーブル作成時にはプライマリーキーとソートキーしか設定できない。
カラムを追加するには、テーブル作成後にテストデータのの入力と共にカラムの設定をしなければならない。
テーブル名:user_authentication
カラム:userID(プライマリーキー)、password


Step2 Lambdaでユーザー新規追加関数と認証機能関数の2つの関数を作る

①クライアントからUserIDが送られてきた時にランダムで認証キーを作成してDynamoDBに保存し、認証キーをクライアントに返す関数。(簡略化のため割愛)
②クライアントからユーザーIDとパスワードを渡されたときにDynamoDBの該当データを引っ張り、合っているか確かめる関数。(ソースは下記)

expor
ts.handler = function(event, context, callback){
  console.log(event);var params = {
   "TableName": "user_authentication",
   "Key":{
    "email": event.userID
   }
 };
 console.log('テスト');
 dynamo.getItem(params, function(err, res) {
  if (err){
   callback(null,response);
  } else {
  var response = {"result":""};
  if(event.password === res.Item.password){
   response.result = "認証に成功しました。";
  }else{
   console.log('失敗')
   response.result = "認証に失敗しました。";
  }
  callback(null,response);
  }
 });
};

Step3 API Gateway によって外部からLambdaを呼び出せるようにする(API化する)

APIを作成したら、アクション→メソッドの追加でGETを関数①に紐づけて、POSTを関数②に紐づける。
GETのメソッドリクエストからURLクエリを指定(userIDとpassword)する。
統合リクエストでクライアントから渡されるURLクエリをマッピングする。
content-typeはapplication/jsonにして、マッピングの本文は下記

{
 "userID":"$input.params('userID')",
 "password":"$input.params('password')"
}

これによって、URLクエリがLambdaの第一引数eventに渡される。

Step4 APIをデプロイしてSDKを作成する

まずはリソース毎に「アクション→CORSの有効化」によって外部からアクセスできるように設定します。
そして「アクション→APIのデプロイ」で専用のSDKを作成したら、クライアントで使います。
GETやPOST関数はapigClient.jsに書いているので、その関数を利用することでAPI Gatewayをクライアントから呼び出せます。

下記はSDKを作ってクライアントに適用した場合のGetの例。
・URLクエリはparamsにjson形式で渡す。
・userPluginGetというGETメソッドだが、userPluginというのはAPI Gatewayによってよって名前が変わる。apigClient.jsでGETメソッドの名前をチェックして使うようにする。
・API GatewayからのレスポンスはLambdaのcallbackで返された形式に従う。
(JavaScriptコード)

$('#authenticate').click(function(e) {
 var user_ID = $('#user_id').val();
 var password = $('#password').val();
 var apigClient = apigClientFactory.newClient();
 var params={"userID":user_ID,"password":password};
 var body={};
 var additionalParams = {};
 apigClient.userPluginGet(params,body,additionalParams)
 .then(function(response) {
  $('#result').val(response.data.result);
 }).catch(function(result) {
  //This is where you would put an error callback
  console.log('error:'+result.data);
 });
});

(HTMLコード)

<table border="0">
 <tbody>
  <tr>
   <th>ユーザID:</th>
   <td><input id="user_id2" size="24" type="text" value="testuser" /></td>
  </tr>
  <tr>
   <th>認証キー:</th>
   <td><input id="password" size="24" type="password" value="********" /></td>
  </tr>
  <tr>
   <td colspan="2"><button id="authenticate" type="button">認証する</button></td>
  </tr>
 </tbody>
</table>
<table>
 <tbody>
  <tr>
   <th>認証結果:</th>
   <td><input id="result" size="25" type="text" /></td>
  </tr>
 </tbody>
</table>

エラーが出た時などに修正する時の注意点

・API Gatewayの修正をした場合は、APIをデプロイし直し→SDKを再度作成→クライアントに適用を行うこと。
・task timeoutというエラーはLambdaのタイムアウト時間が短すぎるため、Lambda設定画面のconfiguration→Advanced Settingからタイムアウト時間を延ばす。
・”Process exited before completing request.”はデータベースのへの検索時にクエリ指定を間違えた時に出るエラーなので、クライアントのparams、API Gateway のクエリ文字列設定とマッピング設定、Lambda関数のクエリをチェックする。

今回は以上となります。

lambda、dynamoの組み合わせで、サーバーレスxxxxが簡単に構築できます。

みなさんもぜひチャレンジしてみて下さい!