内容
本記事はrailsアプリから、ユーザのSlackと連携するためのアクセストークンをOAuthで取得して、メッセージを送る処理を書いています。
なので、自分の所属するチームにメッセージを送るというより、見知らぬ誰かのチームに送るサービスをイメージしています。
Incomming webhooks使えばOAuthいらんやん、とか言われそうですが
ユーザ側で設定しなきゃいけないのは面倒くさいと思うので。
(普段slackにブラウザでアクセスする人ってあんまいないんじゃ、、、とかは気にしない)
環境
- macOS High Sierra 10.13.3
- ruby 2.5.0
- rails 5.1.4
事前準備編
Slackにチーム登録
Slackにはチームがすでに登録されている前提です。
Slackにアプリ登録
まずは、SlackAPIを叩くためにSlackにアプリを登録しておきます。
ブラウザでslackにログインしてから、こちらのurlにアクセス
https://api.slack.com/
表示されるフォームで適当にアプリの名前を入力して、アプリを登録したいチームを選択
Basic InformationのApp CredentialsでClient IDとClient Secretを控えておきます。
ちなみにClient Secretは関係者以外に見せてはいけないので、管理には注意してください。
git載せるダメ、絶対
下にVerification Tokenというものもありますが、メッセージを送るだけならば不要です。
続いて、OAuth連携をするための設定を行います。
左サイドのOAuth & Permissionsをクリックします。
Redirect URLsはslackで認証後に自分のアプリに戻るためのurlです。
後でいくらでも変更可能なので、適当に登録しておきます。
ここでは認証後にhttp://localhost:3000/slack/auth へ戻してもらうことにしましょう。
意外に気づかないのが、"Add a new Redirect URL"で記入した後、"Save URLs"を押さないと登録されないので注意。
次は下にスクロールしてScopeを設定します。
このアプリが認証されたユーザに対して行うことができる操作をここで設定します。
twitterとかでアプリ連携する時に、「このアプリは〇〇を行うことができます」みたいな感じで表示されるアレ
今回はメッセージが送れれば良いので、"Send messages as hogehoge (chat:write:bot)"のみ、
権限は最小限にするのが鉄則だから不用意になんでもかんでも設定しない
これもSave Changesをお忘れなく。
これでslack側の設定は完了!!
rails
前準備
細かい所は気にしないでslack連携を行う場所を適当に作っていきます。
rails new slack_auth
rails generate controller slack index
Rails.application.routes.draw do
resources :slack do
collection do
get :auth
end
end
end
今回はslackへのメッセージ送信用にslack-apiというgemを利用します。
slackで提供されるapiのラッパーなので、
必要なパラメータはcurlなどで叩く場合と基本的に同じなはずです。
Gemfileに以下を追記してbundle install実行
gem 'slack-api'
bundle install
使用するときはrequireしてあげる必要があるので、initializersにそれ用のファイルを追加します。
require "slack"
Slackの承認ページアクセス
Slackの承認ページへアクセスするための処理を作りましょう。
今回はnewアクションでリダイレクトさせるようにします。
クエリパラメータには要求するscopeと、先程取得したclient idをつけてください。
実際に利用する際は環境変数を使うなどして、直接書かないことをおすすめします。
class SlackController < ApplicationController
def index
end
def new
redirect_to ("https://slack.com/oauth/authorize\?scope\=chat:write:bot\&client_id\=" + "取得したclient_id")
end
def auth
end
end
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>
<h1>Slack#index</h1>
<%= button_to 'Slack OAuth', new_slack_path, :method => :get %>
ボタンをクリックすると、Slackの承認ページが表示されます。
アクセストークン要求
Authorizeを押すと、
先程redirect_urlで設定した指定したurl(/slack/auth)へ
codeというクエリパラメータが付加された状態でリダイレクトされます。
アクション側ではこのcodeを使って、アプリからSlackへアクセストークンを要求することになります。
slack-apiでSlackクラスが用意されるため、これでアクセストークンを取得します。
例によってclient_secretは直接書かないことをおすすめします。
def auth
auth_result = Slack.oauth_access({client_id: "取得したclient_id", client_secret: "取得したclient_secret", code: params[:code], scope: "chat:write:bot"})
if auth_result["ok"]
redirect_to slack_index_path, notice: "テスト"
else
redirect_to slack_index_path, alert: "error: " + auth_result["error"]
end
end
auth_resultの中身はこんな感じ
# 成功した時
{"ok"=>true,
"access_token"=>"xxxx-xxxxx-xxxxx-xxxxx-xxxxx",
"scope"=>"identify,chat:write:bot",
"user_id"=>"XXXXXXXXX",
"team_name"=>"slaaaaack",
"team_id"=>"XXXXXXXXX"}
# 失敗した時
{"ok"=>false, "error"=>"code_already_used"}
このアクセストークンがSlackへの連携処理を行う際に必要な情報になります。
現状トークンに有効期限はなく、ユーザが再生成しない限り
同じトークンを使い続けられるそうです。
https://qiita.com/subarunari/items/3e4c6060fcefd4c65257
メッセージ投稿
取得したアクセストークンを使って、Slackにメッセージを投稿します。
メッセージ投稿はユーザの表示名と投稿先のチャンネルを指定して行います。
def auth
auth_result = Slack.oauth_access({client_id: "取得したclient_id", client_secret: "取得したclient_secret", code: params[:code], scope: "chat:write:bot"})
if auth_result["ok"]
Slack.client({token: auth_result["access_token"]})
.chat_postMessage(text: "グッド!!", username: "test_auth", channel: "#random")
redirect_to slack_index_path, notice: 'slackにメッセージを送りました'
else
redirect_to slack_index_path, alert: "error: " + auth_result["error"]
end
end
Slackの承認ページでAuthorizeを押すと
[画面]
[Slack]
無事メッセージが送られました