Google Cloud PlatformでSlackBot開発【Slack App認証編】
この前Herokuでbot動かすとこまでやったけど, 今回はGCP(Google Cloud Platform)で動かそうと思います.
GCP動かしてみたかった. Events APIも使ってみようというのが理由です.
でも, HTTPを用いるEvent APIは30,000 Events/hが上限らしいので, 一応注意.
(https://api.slack.com/events-api#rate_limiting)
という事で, GCP(Google Cloud Platform)上でbotを作成していきます.
今回は認証まで.
Slack Appの作成
前回とほぼ同じだと思うけど, 一応書く.
Slack APIのトップページから Start Building >> Create New App で新しいSlackアプリを作成できる.
Slack API | Slack
アプリ作成直後のページがこんな感じ.
左のサイドメニューから各種設定をする.
まず, Basic Information の App Credentials をみると, Client ID や Client Secret というのが書いてある.
これは, アプリ自体の固有なIDの事らしい.
次に, Bot Users ではBotの設定ができる.
Add a Bot User を押すと, 名前などを設定でき, Add Bot User と押すと, アプリを追加した際にワークスペース上にBotが登場する.
次に, OAuth & Permissions の Scopes の設定.
ここでは, アプリが使用できるAPIの種類を設定する.
あまり沢山のスコープを設定すると, アプリをSlackに公開する際に大変らしいので, 必要最低限の権限だけ追加する.
APIのメソッドとスコープの対応関係は以下に記載されている.
そして, 最後にOAuth Tokens& Redirect URLs だが, GCPとの連携が必要なので後ほど述べる.
以上でSlack Appの最低限の設定は終わり.
次はGCPの設定に移っていく.
GCPの登録
GCPのページに行くとトップにTry It Freeと書いてある.
GCPではお試しとして, 12ヶ月$300分が使えるらしい.
(2018年4月30日現在)
お試し期間を過ぎてしまっても, 急に請求が来ることは無いらしい. (本当か?)
一番性能の低いVM1個だけだったら無料で使えたりというような, サービス毎に無料枠が設定されてることもある.
無料枠の範囲内ならお試し期間過ぎても大丈夫そう.
Try It Free を押すと登録画面に移動する.
利用規約の承諾をして進むと, 住所とクレジットカードの番号を入力する画面に移動する.
必要事項を入力して, 無料トライアルを始める を押すと登録が完了する.
クレジットカード番号を入力するが, もし仮に課金が開始されようとなるときはちゃんとGoogleから連絡来て承認してかららしい.
とりあえず, 安心.
(多分, 自分以外誰も使わないレベルでの運用なら課金なんて微々たる気がするけど)
GCPとSlack Appの連携
今回はSlack Appを動かすために必要な認証をGCP上で行う.
Slack Appはワークスペースに追加する際に, 特定のURLへリダイレクトをできる.
このリダイレクトを用いて認証する事で, HTTPの通信でトークンを発行する事ができる.
以下に今回の構成図を示す.
先ほど言ったリダイレクト先をGCPのCloud Functionsに設定する.
プログラムのログとかはStackdriverで確認できるみたい.
GCP SDKのインスール
ローカルのターミナル上でGCPを操作するために, GCP SDKをインストールする.
以下のURLにアクセスして, 自分の環境にあったファイルをダウンロードする.
Installing Google Cloud SDK | Cloud SDK Documentation | Google Cloud
以下のコマンドを実行してインストールする.
ちなみに, gcloud initをするとブラウザが立ち上がるので使用するGoogleアカウントを選択すると自動でプロジェクトの一覧とか読んできてくれる.
すごくべんり
cd ~/Downloads tar zxvf ./google-cloud-sdk-199.0.0-darwin-x86_64.tar.gz ./google-cloud-sdk/install.sh ./google-cloud-sdk/bin/gcloud init
環境変数の設定
認証にはAppのIDが必要だけど, ソースに直書きするのも色々問題なので, 環境変数から読み込むことにする.
GCP上での環境変数の設定はconfigという単位で管理される.
以下でconfigを作れる, 最後の引数がconfig名である.
gcloud beta runtime-config configs create (config名)
configのリストは以下で確認できる.
gcloud beta runtime-config configs list
今回は Client ID と Client Secret を環境変数にセットする.
SlackのAppの設定画面の Basic Information >> App Credentials から値を確認する.
環境変数の設定は以下のコマンドで実行できる.
gcloud beta runtime-config configs variables set (変数名) (値) --config-name (config名) --is-text
セットされた変数の名前と変数の値はそれぞれ以下のコマンドで確認できる.
gcloud beta runtime-config configs variables list --config-name (config名) gcloud beta runtime-config configs variables get-value (変数名) --config-name (config名)
Cloud Functionsの作成
本題のCloud Functionを作成する.
GCPのホームから Cloud Functions を選択して関数を作成する.
名前と割り当てるメモリを選ぶ.
メモリは分からなかったので最小の128MBを選んだ.
トリガーはリダイレクトで実行するのでHTTPとする.
トリガーの以下にURLが表示されるので, これを後でリダイレクトURLとして設定.
次に実行する関数を記述する.
SlackAppの認証の流れは次の通りである.
- ワークスペースにアプリを追加する.(ユーザがブラウザ上で実行)
- 設定したサーバのURLにリダイレクト, リクエストはcodeというgetパラメータを持つ
- サーバはSlackAPIにcode, client id, client secretを付加したGETリクエストを送る
- Slackからjsonが返ってくる(okパラメータがtrueだったら認証成功)
今回はとりあえず, 認証を行った後は最終的に返ってくるjsonをそのまま表示するようにした.
index.js
/** * Responds to any HTTP request that can provide a "message" field in the body. * * @param {!Object} req Cloud Function request context. * @param {!Object} res Cloud Function response context. */ const request = require('request'); const rcloadenv = require('@google-cloud/rcloadenv'); exports.onRedirectSlackOAuth = (req, res) => { //リダイレクトのリクエストの検証 if (req.method !== 'GET') { let error_message = "Illegal Request, wrong method"; console.log(error_message, req.method); res.status(405).send(error_message); return; } if (req.query.code === undefined) { let error_message = "Illegal Request, no required query" console.log(error_message, req.query); res.status(400).send(error_message); return; } let code = req.query.code; //環境変数の取得 rcloadenv.getAndApply('test-slackbot', {}).then((env) => { if (env.CLIENT_ID === undefined || env.CLIENT_SECRET === undefined) { console.error('Failure: TOKEN_ID and TOKEN_SECRET is not set'); let error_message = 'Sorry Failure OAuth by Server Error'; res.status(500).send(error_message); return; } //Slack APIを叩く let client_id = env.CLIENT_ID; let client_secret = env.CLIENT_SECRET; let url = 'https://slack.com/api/oauth.access'; request.get({ uri: url, headers: { 'Content-type': 'application/json' }, qs: { client_id: client_id, client_secret: client_secret, code: code }, json: true }, function(err, req, data) { if (data) { if (data.ok) { //認証成功 let access_token = data.access_token; let team_name = data.team_name; let team_id = data.team_id; let message = "OAuth Successful" console.log(message, data); res.status(200).send(message); } else { let error_message = 'OAuth Failure'; console.error(error_message, data.error); res.status(500).send(error_message); } } if (err) { let error_message = 'OAuth Failure'; console.error(error_message, err); res.status(500).send(error_message); } }); }).catch((err) => { console.error('Failure: Config test-slackbot is not found'); let error_message = 'Sorry Failure OAuth by Server Error'; res.status(500).send(error_message); }); };
package.json
{ "name": "Test-SlackApp-OAuth", "version": "0.0.1", "dependencies": { "@google-cloud/rcloadenv": "^0.2.1", "request":"^2.8.0" } }
動作確認
Cloud Functionsの設定にあるURLをSlack Appに設定する.
OAuth & Permissions >> OAuth Tokens & Redirect URLs >> Redirect URLs で Add a new Redirect URLでCloud FunctionsのURLをセットする.
そして以下のURLにブラウザからアクセスする.
https://slack.com/oauth/authorize?client_id=(アプリのClient ID)&scope=(アプリのスコープ)
以下のページが出たら, Authorizeを押す.
以下のようなJSONが返ってきたら, 認証は成功.