LoginSignup
8
8

More than 5 years have passed since last update.

Slack認証 + Rails によるログイン画面を一から作る方法

Posted at

概要

Rails + Slack の認証機能で簡単なログイン画面を作る。

今回はあえて slack-omniauth など専用の gem などは使わずに、一から作ってみましょう。

お急ぎ便

すぐにぱっと試したい人は下記のコードをcloneしてきて、
環境変数をセットし、サーバを起動したら試せます。

Slack 側の用意

Slackにログインする

  • 連携したいSlackのチームにログインをしておいてください

連携用の鍵を作成する

create.jpg

  • 作成が出来ると作成した Your Apps に作成した App の情報が表示されるようになります

リダイレクト先URLを設定する

  • Your Apps から先ほど作った App の名前のリンクを押してください

  • OAuth & Permissions を押下します

oauth.jpg

  • ユーザの認証後にリダイレクトするURLを設定します

今回は開発のローカルにリダイレクトするために下記で設定します。

http://localhost:3000/sessions/acs

※host名やポートは適宜設定してください。

設定ができたら Save Changes を押して設定を保存してください。

またこの値は後程出てくる redirect_uri の値として使うのでメモしておいてください。

必要なパラメータをメモしておく

  • client_id, secret_key を Rails 使用するのでコピペしてメモ帳などに張り付けておいてください

clientid.jpg

show ボタンを押すと secret_key が表示されます

以上で Slack 側での用意は終了です。

続いて Rails のセッティングをしていきます。

Rails 側の用意

アプリの作成

  • 作業ディレクトリを作成して移動しましょう
mkdir slack_login
cd $_
  • Rails アプリを作成します
bundle init
Gemfile
source "https://rubygems.org"
gem "rails", '~> 5.0.0'
bundle
bundle exec rails new . -N --skip-active-record --skip-bundle

連携に必要なパラメータの用意

  • 連携に必要なパラメータは下記になります
パラメータ 説明
client_id Slack連携を行う識別用ID
secret_key Slack連携を行う認証用key
scope アプリに許可する権限(とりあえず『identify』と設定しておけば良い )
team_name 認証先のチーム名
state リダイレクト元識別key(自分で作成)
redirect_uri 認証後のリダイレクト先
  • client_id, secret_key, redirect_uri については Slack側の用意 の項目で準備したものを使います。
  • scope はとりあえず identify と設定しておきます。
  • team_name は連携をする Slack のチーム名を設定します。
  • state は 認証時に Rails からポストする値です。これは Slack からそのまま返却されます。
    • よって state は自分のアプリが Slack にリクエストを送り、そのときに返ってきたレスポンスであることを証明するのに使います。

シークレットな値になるので環境変数に値をセットし、 Rails からは定数として使うようにしましょう。

  • 環境変数のセット
環境変数 セットする値
SLACK_CLIENT_ID client_id
SLACK_SECRET_KEY secret_key
SLACK_TEAM_NAME team_name
SLACK_SCOPE state
SLACK_REDIRECT_URL redirect_uri
SLACK_STATE_CODE state code
  • 環境変数を定数に入れる

お好きな gem を使うなりしてください。
今回は easy_settings という gem を使って定数管理をするようにします。

Gemfile に 以下の記載を追加して bundle install してください。

Gemfile
gem 'easy_settings'
bundle

続いて config/settings.yml を作成します。

config/settings.yml
default: &default
  slack:
    client_id: "<%= ENV['SLACK_CLIENT_ID'] %>" 
    secret_key: <%= ENV['SLACK_SECRET_KEY'] %>
    team_name: <%= ENV['SLACK_TEAM_NAME'] %>
    scope: <%= ENV['SLACK_SCOPE'] %>
    redirect_url: <%= ENV['SLACK_REDIRECT_URL'] %>
    state: "<%= ENV['SLACK_STATE_CODE'] %>"
    url:
      auth: https://slack.com/oauth/authorize?
      info: https://slack.com/api/oauth.access?
development:
  <<: *default

test:
  <<: *default

production:
  <<: *default                   

これで例えば client_id を取得したかったら下記のように書くことで取得できます。

EasySettings.slack.client_id
#=> xxxxxxxxxx

Slackとの連携用Classを作成

  • Slackにリクエストを送信する準備

Slackにリクエストを送る準備をします。ここも自分の好きなgemなどを使ってください。
今回は httpclient を使います。Gemfileに以下を記載して bundle install してください。

Gemfile
gem 'httpclient'
bundle
  • 連携用Class(SlackConnector)を作成

以下のような Class を lib/ 配下に作成します。

lib/slack_connector.rb
class SlackConnector

  def initialize
    @client_id     = EasySettings.slack.client_id.to_s
    @client_secret = EasySettings.slack.secret_key
    @scope         = EasySettings.slack.scope
    @team_name     = EasySettings.slack.team_name
    @redirect_uri  = EasySettings.slack.redirect_url
    @state         = EasySettings.slack.state
  end 

  def auth_path
    "#{auth_host}client_id=#{@client_id}&state=#{@state}&scope=#{@scope}&team=#{@team_name}&redirect_uri=#{@redirect_uri}"
  end 

  def get_info(code)
    path = "#{acs_host}client_id=#{@client_id}&client_secret=#{@client_secret}&code=#{code}&redirect_uri=#{@redirect_uri}"

    hc = HTTPClient.new
    response = hc.get(path)
    res_json = JSON.parse(response.body)

    HashWithIndifferentAccess.new(res_json)                                                                                                                                                                        
  end

  private

  def auth_host
    EasySettings.slack.url.auth
  end

  def acs_host
    EasySettings.slack.url.info
  end
end

説明

やってることは簡単で以下の2つの処理をさせています。

  1. Slack認証用のURLを作成する
  2. 認証完了後の値を元にユーザの情報を取得する
  • Slack認証用のURLを作成する

Slack認証用のURLにはパスパラメータで

  • client_id
  • state
  • scope
  • redirect_uri

の情報が必要です。

※各パラメータを空だとしたらこんなURLにアクセスさせる

https://slack.com/oauth/authorize?client_id=&state=&scope=&team=&redirect_uri=

これらの各パラメータを initialize のタイミングでインスタンス変数に格納しています。

  • 認証完了後の値を元にユーザの情報を取得する

こちらもやっていることは Slack認証用のURLを作成する と同じです。

各パラメータをセットして、 Slack の Web API を叩き、返り値をセット返すようにしています。

ポイント二つです。

まず引数で受け取る codeSlack認証用URL からリダイレクトした後に含まれる値で、
ログイン認証を終えたユーザを識別する値 にもなります。

次に返り値は json で返ってくるので hash へと変換をさせています。
その際文字列の hash に対して symbol でアクセスができるように
HashWithIndifferentAccess を使用しています。

  • lib 配下を自動で読み込む設定を追加

config/application.rb に以下を追記

config/application.rb
Rails.application.configure do
  config.autoload_paths += %W(#{config.root}/lib)
end

Controller を作成する

ユーザに対してSlack認証させ、その結果を受け取り、セッションに格納する Controller を作成します。

  • ControllerView を作成する

以下のコマンドで一気に作ってしまいます。

bundle exec rails g controller sessions index new acs

作成された app/controllers/sessios_controller.rb を以下のように修正します。

controller/sessions_controller.rb
class SessionsController < ApplicationController

  def index
  end 

  def new 
    client = SlackConnector.new
    redirect_to client.auth_path
  end 

  def acs 
    state = params[:state]
    raise "invalid" if state != EasySettings.slack.state || params[:error].present?

    client = SlackConnector.new
    code   = params[:code]

    # ユーザの情報を取得
    res = client.get_info(code)

    if res[:ok]                                                                                                                                                                                                    
      raise "invalid team" if res[:team_name] != EasySettings.slack.team_name

      session[:user] = {}.tap do |u| 
        u[:id]            = res[:user_id]
        u[:access_token]  = res[:access_token]
        u[:time]          = Time.zone.now
      end 

      # ログイン成功後のリダイレクト先。今回はrootへ戻します。
      redirect_to root_path, notice: "ログインテスト成功"
    else
      redirect_to root_path, notice: "ログイン失敗"
    end 
  rescue
    redirect_to root_path, notice: "ログイン失敗"
  end 
end
  • ログイン画面を作成

以下のように app/view/sessions/index.html.erb を修正

view/sessions/index.html.erb
<h1>Slackログイン</h1>
<%= link_to 'Slackログイン', sessions_new_path %>                                                                                                                                                                  
<% if flash[:notice] %>
  <h4><%= flash[:notice] %></h4>
<% end %>
  • ルーティングの設定

rootにアクセスしたときにログイン画面に遷移するよう以下のパスを追加

config/routest.rb
root controller: :sessions, action: :index

試してみる

さっそく試してみましょう。

  • サーバを起動する
bundle
bundle exec rails s
  • ログイン画面へ遷移する

以下のように表示されていればOKです。

login.jpg

Slackログインリンク を押下しましょう。

すると Slack の認証画面へ遷移すると思います。

slackauth.jpg

Authrize を押したらログイン画面に「ログイン成功」の文字が出てきます。

これでとりあえず Slack を利用したログイン画面は完成です。

まとめ

今回は RailsSlack の認証を使ったログイン画面を一から丁寧に作成していきました。

上記のコードをまとめたものを以下の Github にアップしています。

手元で実際に動かして試してみたい方はご利用ください。

参考

Slack の認証後と ユーザ情報取得後のパラメータの値は以下のようになっています。

  • Slack認証画面のリダイレクト後
[1] pry(#<SessionsController>)> params
=> <ActionController::Parameters {"code"=>"xxxxx", "state"=>"xxxxx", "controller"=>"sessions", "action"=>"acs"} permitted: false>
  • ユーザ情報取得後
[1] pry(#<SessionsController>)> res
=> {"ok"=>true, "access_token"=>"xoxp-xxxx", "scope"=>"identify", "user_id"=>"Uxxxx", "team_name"=>"xxxx", "team_id"=>"Txxxx"}
``
8
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
8