api gateway + lambdaでline通知サービス構築

20
API Gateway + Lambda で LINE ででササササササ 2016 で 10 で 6 で ででで

Upload: kenichirou-kimura

Post on 16-Apr-2017

350 views

Category:

Technology


8 download

TRANSCRIPT

Page 1: API Gateway + LambdaでLINE通知サービス構築

API Gateway + LambdaでLINE通知サービス構築 

2016年 10月 6日木村健一郎

Page 2: API Gateway + LambdaでLINE通知サービス構築

名前:木村健一郎所属:株式会社コム・アンド・コム    JAWS-UG福岡   さくらクラブ福岡 IoTお仕事:技術に関することはなんでも好きな言語: perl好きな DB: PostgreSQL

Page 3: API Gateway + LambdaでLINE通知サービス構築

今日のお題:  Lambdaで LINEに通知するサービスを作る

Page 4: API Gateway + LambdaでLINE通知サービス構築

LINE Messaging API/LINE Notify

• 2016/4/7に BOT APIは公開されてた• 利用者からの入力を受けて、それに返す

•Messaging APIが先日 (2016/9/29)公開された• 外部から API叩いて LINEに送信できる• かなり色々出来そう (まだ試してない )

• LINE Notifyの公開 (2016/9/29)• 外部から API叩いて LINEに通知を送れる• Mackerelや IFTTTが公開済み

•さっそく Notifyで遊んでみた• せっかくなんで Serverlessフレームワーク使ってみた

Page 5: API Gateway + LambdaでLINE通知サービス構築

準備するもの

• LINE自体のアカウントPCからログインできるようにしておく必要があります• LINE Developerへの登録この辺から登録しましょうhttps://business.line.me/ja/services/bot• Nodeと pythonが動くマシン私は Node6.6.0/Serverless 0.5.6/Python2.7.12で試しました

Page 6: API Gateway + LambdaでLINE通知サービス構築

処理の流れAPI Gateway + Lambda

①アクセス

LINEのサーバ

②リダイレクト

③ログインページ

④認証

⑤認証情報 (code)返信

⑥oauth APIコール

⑦token返信

⑧token使ってメッセージ送信

⑨メッセージプッシュ

Page 7: API Gateway + LambdaでLINE通知サービス構築

今回の構成

インターネットhttpアクセス

CSRF対策 /oauthのトークンと利用者を紐付けるキーの保存

Page 8: API Gateway + LambdaでLINE通知サービス構築

準備IMAロールや DynamoDBの設定を先にやっておきましょう (詳細略 )

• LINE notifyのサイトでアプリケーションを登録しておきます• https://notify-bot.line.me/ja/• アプリケーション名はメッセージが「 [アプリ名 ]ほげほげ」という感じになります• クライアント IDと秘密鍵をメモっておきます• Callbackはアプリ作成時に入力求められますが、適当でいいです

• DynamoDBのテーブル作成• テーブル名「 line-message」、スキーマは「 state」というテキストだけ

• IAMユーザならびにロールの作成• serverless用に AdministratorAccessのユーザ• Dynamodbの読み書きが出来るロール

Page 9: API Gateway + LambdaでLINE通知サービス構築

serverlessをインストールしてプロジェクト作成%sudo npm install serverless –g%sls project create _______ __| _ .-----.----.--.--.-----.----| .-----.-----.-----.| |___| -__| _| | | -__| _| | -__|__ --|__ --||____ |_____|__| \___/|_____|__| |__|_____|_____|_____|| | | The Serverless Application Framework| | serverless.com, v0.5.6`-------'

Serverless: Initializing Serverless Project... Serverless: Enter a name for this project: (serverless-ryqpyr)line-messageServerless: Enter a new stage name for this project: (dev) devServerless: For the "dev" stage, do you want to use an existing Amazon Web Services profile or create a new one? Existing Profile > Create A New ProfileServerless: Please enter the ACCESS KEY ID for your Admin AWS IAM User: *****Serverless: Enter the SECRET ACCESS KEY for your Admin AWS IAM User: *****Serverless: Enter the name of your new profile: (hoge_dev) Serverless: Creating stage "dev"... Serverless: Select a new region for your stage: us-east-1 us-west-2 eu-west-1 eu-central-1 > ap-northeast-1Serverless: Creating region "ap-northeast-1" in stage "dev"... Serverless: Deploying resources to stage "dev" in region "ap-northeast-1" via Cloudformation (~3 minutes)...

Page 10: API Gateway + LambdaでLINE通知サービス構築

最初にリダイレクトする /authと、認証情報のコールバックを受ける /callbackの 2つのエンドポイントを作成

エンドポイントの作成

%sls function create auth%sls function create callback

Page 11: API Gateway + LambdaでLINE通知サービス構築

CSRF対策の文字列を作って DynamoDBに保存して、リダイレクトするコードを auth/handler.pyに書きます

authの作成 (1)

from __future__ import print_function

import jsonimport loggingimport uuidimport hashlibimport boto3

log = logging.getLogger()log.setLevel(logging.DEBUG)dynamodb = boto3.resource('dynamodb')table = dynamodb.Table('line-message')

def handler(event, context): log.debug("Received event {}".format(json.dumps(event))) token = hashlib.md5(str(uuid.uuid4())).hexdigest() table.put_item( Item={ "state" : token } ) return {"location" : "https://notify-bot.line.me/oauth/authorize?response_type=code&client_id=***&redirect_uri=https://******/dev/callback&scope=notify&resonse_mode=form_post&state="+token}

Page 12: API Gateway + LambdaでLINE通知サービス構築

302でリダイレクトするように api gatewayの設定を auth/s-function.jsonに書きます。 DynamoDBにアクセスするためのロールもここに記載します。

authの作成 (2)

・・・・ "customRole": "arn:aws:iam::***************",・・・・・ "responses": { "400": { "statusCode": "400" }, "default": { "statusCode": "302", "responseParameters": {       "method.response.header.Location" : "integration.response.body.location" },

ハンドラーの戻り値を Locationヘッダに出す

Page 13: API Gateway + LambdaでLINE通知サービス構築

LINEサーバから渡された情報を元に Oauthを行って、その結果を HTMLで表示します。 callback/handler.pyに書きます。前半の、受け取った CSRFトークンが正しいかの検証部分です。

callbackの作成 (1)

from __future__ import print_function

import jsonimport loggingimport boto3import urllibimport urllib2import jsonlog = logging.getLogger()log.setLevel(logging.DEBUG)dynamodb = boto3.resource('dynamodb')table = dynamodb.Table('line-message')

def handler(event, context): res = table.get_item( Key={ 'state':event['state'] } )

if res['Item']: table.delete_item( Key={ 'state':event['state'] } )

Page 14: API Gateway + LambdaでLINE通知サービス構築

後半の oauthを呼ぶ部分です

callbackの作成 (2)

url = 'https://notify-bot.line.me/oauth/token' postvalue = { 'grant_type' : 'authorization_code', 'code' : event['code'], 'redirect_uri' : 'https://********/dev/callback', 'client_id' : ‘**********', 'client_secret' : ‘*********', } postdata = urllib.urlencode(postvalue); req = urllib2.Request(url,postdata) response = urllib2.urlopen(req) page = response.read() return page else: return "not found"

Page 15: API Gateway + LambdaでLINE通知サービス構築

ハンドラーへのパラメータ受け渡しと、結果を text/htmlで返す api gatewayの設定を callbac/s-function.jsonに書きます。DynamoDBにアクセスするためのロールもここに記載します (text/htmlで返すのは不要かも・・ )。

callbackの作成 (2)

・・・・ "customRole": "arn:aws:iam::***************",・・・・・ "requestTemplates": { "application/json": { "state" : "$input.params('state')", "code" : "$input.params('code')" } },  "responses": { "400": { "statusCode": "400" }, "default": { "statusCode": "200", "responseParameters": {}, "responseModels": { "text/html;charset=UTF-8": "Empty" }, "responseTemplates": { "text/html;charset=UTF-8": "$input.path('$')" } } }

ここで入力のテンプレートを定義するとハンドラーの第 1引数 (event)にハッシュで渡る

出力を text/htmlとして、 Velocityの出力を出すようにする

Page 16: API Gateway + LambdaでLINE通知サービス構築

デプロイします。カーソルキーとリターンで全ての functionと endpointを選んで「 Deploy」を選びます

デプロイ

%sls dash deploy| _ .-----.----.--.--.-----.----| .-----.-----.-----.| |___| -__| _| | | -__| _| | -__|__ --|__ --||____ |_____|__| \___/|_____|__| |__|_____|_____|_____|| | | The Serverless Application Framework| | serverless.com, v0.5.6`-------'

Use the <up>, <down>, <pageup>, <pagedown>, <home>, and <end> keys to navigate.Press <enter> to select/deselect, or <space> to select/deselect and move down.Press <ctrl> + a to select all, and <ctrl> + d to deselect all.Press <ctrl> + f to select all functions, and <ctrl> + e to select all endpoints.Press <ctrl> + <enter> to immediately deploy selected.Press <escape> to cancel.

Serverless: Select the assets you wish to deploy: auth > function - auth endpoint - auth - GET callback function - callback endpoint - callback - GET - - - - - Deploy Cancel

Page 17: API Gateway + LambdaでLINE通知サービス構築

動かしてみましょう

• authのエンドポイントにアクセス• LINEの認証後、メッセージをどのグループで受け取るかを選ぶ• 1対 1またはグループが選べるようです• グループの場合は LINE Notifyをグループに招待します

• うまくいったらトークンが表示されるのでコピペしてメッセージ送ってみましょう

%curl -X POST -H "Authorization: Bearer ******" -F 'message=テストです ' https://notify-api.line.me/api/notify

Page 18: API Gateway + LambdaでLINE通知サービス構築

注意

• 2016年 10月 4日時点での情報です• LINE Messaging APIも serverlessの使い方も変わっている可能性はあります。必ず最新の公式ドキュメントを参照してください

• Serverless 、もうすぐ 1.0が出てずいぶん変わってるとか・・

• リダイレクトだけ (auth)を Lambdaでやる意味があるかというと微妙?

• トークンの管理は手を抜いています• エラーハンドリングもしてません• DynamoDBの not foundは try-catchでチェック?

「とりあえず試してみた」のレベルなので以下の点はご注意を

Page 19: API Gateway + LambdaでLINE通知サービス構築

感想

• 受信メッセージが「 LINE Notify」っていうグループにまとめられるのがちょっと残念

• 直接おしゃべりみたいなのは BOT APIやMessaging APIでやりましょうってことかと

• LINE APIの Rate limitは 1000アクセス /時・トークン。実用上まず問題ないレベル。

• Serverlessフレームワーク便利だけど、どんどん変わっていってて情報が錯綜気味?・外部ライブラリをどこに置いといたらいいのか分からなかった

• 「 serverless」ってググりにくい・・ (´ ・ ω ・ `)

• テキスト送る程度の個人用途なら、アプリ登録までしないでも tokenだけ取得も可能なのでここまで作らなくても OK

• もっと言うなら IFTTT + Makerで十分かも (元も子もない )

Page 20: API Gateway + LambdaでLINE通知サービス構築