とりとめも

藻類が学んだり感じたりしたことを未来の自分のために書き留めるところ

RailsでTwitterのユーザー情報と連携して認証を行う

はじめに

Ruby on RailsTwitterのユーザー情報を使用して認証を行う方法についてまとめます。

前回の記事でネタにした自作の練習アプリ「えもったー」で使った方法です。

よくあるアプリごとのユーザー登録・管理機能は用意せず、Twitterのユーザー情報でログイン・ログアウトを行う実装となります。
Twitter登録してないとログインできないし、Twitter登録していれば、何も追加の情報(パスワード等)は無しでログインできる。シンプル。

基本的な処理の流れとしては、gem「omniauth-twitter」でtwitter APIにアクセスして、返ってきたユーザー情報をsession変数に格納するというものです。

・・・omniauth-twitterのドキュメントに従ってるだけといえばそれまでなのですが。

環境

「えもったー」と同じ環境です。

下準備

Twitter APIのアプリケーション登録をする

下記サイト(Twitter Developers)で、Twitter APIを使用したアプリを作るための登録を行います。

https://dev.twitter.com

画面下部の「Manage my apps」から自分のTwitter IDでログインして、促されるままにCreate New Appすれば問題ないと思います。

API KEYを確認する

登録したら、Keys and Access Tokensタブを開き、API KeyとAPI Secretの値を確認します。

この値が、アプリがTwitter APIを利用する際の認証情報となります。他人にばれないように気をつけないとだめ。

API KEYをアプリに記述する

上記で確認した情報をアプリに記述します。
このような秘密にしたい情報はconfig/secrets.ymlにまとめておくのが習わしらしいです。

というわけで、config/secrets.ymlに以下を書きます。

twitter: &twitter
  twitter_api_key: <%= ENV["TWITTER_API_KEY"] %>
  twitter_api_secret: <%= ENV["TWITTER_API_SECRET"] %>

development:
  secret_key_base: (ひみつ)
  <<: *twitter

test:
  secret_key_base: (ひみつ)
  <<: *twitter

production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
  <<: *twitter

ここでは、API KEYとAPI SECRETは環境変数で定義するようにしています。
実際にアプリを動かす際は、環境変数を代入しておくのを忘れないようにしないといけません。

# export TWITTER_API_KEY=(ひみつ)
# export TWITTER_API_SECRET=(ひみつ)

OmniAuth設定ファイルの準備

今回はユーザー認証機能としてOmniAuthを利用するので、OmniAuthの設定ファイルを作成し、前述のAPI KEYとSECRETを記述します。

OmniAuthの設定ファイルはconfig/initializers/omniauth.rbです。

Rails.application.config.middleware.use OmniAuth::Builder do
    provider :twitter,Rails.application.secrets.twitter_api_key,Rails.application.secrets.twitter_api_secret
end

作っていく

gemの準備

Gemfileに以下を追記します

gem 'omniauth'
gem 'omniauth-twitter'

「はじめに」にも少し書いていますが、omniauth-twitterTwitter APIを利用したユーザー認証機能を提供してくれるgemです。

(取得したユーザー情報を元に、ツイートしたりフォローしたりといった操作を行いたい場合は、twitterというgemを別途使用するのが良さそう)

認証用のコントローラとルーティングを設定する

まず、大まかな認証の経路としては以下の通りです。

  • /auth/twitterへのリクエストが、twitterAPIに飛んでいく
  • twitter側で認証に成功したら、Callbackに設定したURLにリクエストが返ってくる
    • このリクエストにIDなどのパラメータが含まれている
    • CallbackのURLに適切なルーティングを設定し、そのアクションでパラメータを取り出す

今回は、コールバック先はhttp:(railsのルートURL)/auth/twitter/callbackとします。
また、コントローラはsessionsという名前にします。
以下では、そんな感じで色々と作っていきます。

ルーティング

以下の内容をroutes.rbに追記します。

  get '/auth/twitter/callback', to: 'sessions#create'
  get '/logout', to: 'sessions#destroy'

/auth/twitterについてはroutes.rbに書かなくてもomniauth-twitterの機能で自動的にルーティングしてくれる模様です。
そのためコントローラとアクションも書かなくて大丈夫です。

コントローラ作る

# rails generate controller Sessions create destroy

ここまでで試しにブラウザからhttp://(railsのルート)/auth/twitterにアクセスしてみます。
たぶん、tiwtterのアプリ認証画面が表示され、認証するとsessions#callbackのデフォルトのビューが表示されるはずです。

あとはtwitterのユーザー情報をuserモデルやsessionに持たせてあげればオッケーです。

コントローラの中身は後で書くことにして、まずはモデルから作ります。

userモデルを作る

コールバックしてきたリクエストにはtwitterのユーザー情報(twitter idやプロフ画像など)が含まれているので、適宜必要な情報を取り出して、保存したいものはモデルにカラムを用意して保存します。

コールバックで渡されるユーザー情報はrequest.env[‘omniauth.auth’]というハッシュに格納されています。
どんなパラメータがあるかはGithubでomniauth-twitterのREADMEに書かれています。

今回、モデルには以下のカラムを設定することにします。

  • provider
  • uid
  • nickname
  • name
  • image_url
  • description

request.env[‘omniauth.auth’]の中での値もほぼ同名です。image_urlだけimageだけど。

# rails generate model User provider:string uid:string nickname:string name:string image_url:string description:string
# rails db:migrate

セッションとモデルに情報を保管する

以下のリンク先を参考にさせて頂きました。

Userモデル

モデル側には、コントローラが受け取ったrequest.env[‘omniauth.auth’]から情報を取り出してモデルに保存する処理を用意します。

class User < ApplicationRecord
  def self.find_or_create_from_auth(auth)
    provider = auth[:provider]
    uid = auth[:uid]
    nickname = auth[:info][:nickname]
    name = auth[:info][:name]
    image_url = auth[:info][:image]
    description = auth[:info][:description]
    self.find_or_create_by(provider: provider, uid: uid) do |user|
      user.nickname = nickname
      user.name = name
      user.image_url = image_url
      user.description = description
  end
end

元記事から流用しているself.find_or_create_byでは既存ユーザーか否かの判定にproviderとuidを使っていますが、今回のように「twitter認証だけ使う!」場合はuidだけで充分一意になります(providerの値はtwitterしかありえない)。
そのためproviderというカラム自体不要ということになりますが、将来的な拡張のしやすさなどからカラムに含めておくことにしています。

コントローラ

コールバックのアクションから先ほどのメソッドを呼び出し、sessionに情報を格納してあげるだけです。

class SessionsController < ApplicationController
  def create
    user = User.find_or_create_from_auth(request.env['omniauth.auth'])
    session[:user_id] = user.id
    redirect_to root_path
  end

  def destroy
    reset_session
    redirect_to root_path
  end
end

これで準備はおしまいです。

あとはビューで適当なところに/auth/twitterへのリンクを書けば、そのリンクを踏むだけでTwitterで認証が行われ、Twitterのユーザー情報がUserモデルとsessionに取得されるようになります。うれしい。

まとめ

RailsTwitterの情報を用いたユーザー認証の方法をまとめました。
今回のモデルやコントローラの作りはめちゃくちゃシンプルですが、モデルが独自の情報を格納するようになったとしても、Twitterが絡む部分は変わりません。
TwitterAPIからユーザー情報(request.env[‘omniauth.auth’])を取得する部分が要点だと思います。