見出し画像

【Rails】Sorcery で Twitter 認証 [2]

去年の11月末 RUNTEQ の卒業制作で、黙々と勉強するいわゆる「もくもく会」を共有するアプリ「MOKUMOKU」をリリースしました。その制作過程で得られた情報を発信したいと思います。

前回の続き、今回は Sorcery を利用して Twitter 認証を行う際の Rails 側について書きたいと思います。

<バージョン>
 Ruby:2.5.1
 Rails: 5.2.1

大まかな実装の流れ

sorcery による Twitter 認証は、アプリから sorcery を経由して Twitter API を叩いて Twitter へアクセス(ログイン)し、コールバックでアプリ側へ戻って、アプリのユーザー登録と紐付ける流れとなる。
この際、指定しておいた Twitter アカウント情報が取得出来るので必要があれば指定して利用する。

基本的に sorcery 公式 にあるサンプルの通りに実装する。

 - 認証モデル、テーブルの作成
 - sorcery.rb への設定の追加
 - User モデルへのアソシエーションの追加
 - ビューにTwitter 認証を開始するリンクの追加
 - 外部認証コントローラーの追加
 - ルーティングの追加(Twitter認証開始、外部認証コールバック用)

サンプルのままだと上手くいかないところを何点か対応する。

【Rails5.2 対応】

sorcery が Rails5.2 に対応していないため、Gem の指定を修正する。

# Gemfile
gem 'sorcery', github: 'sorcery/sorcery'

また、認証クラスで attr_accessible の記述があるが、既に廃止された記述のため不要。

# app/models/authentication.rb
class Authentication < ActiveRecord::Base
  # attr_accessible は不要
  # attr_accessible :user_id, :provider, :uid
  belongs_to :user
end

【Twitterコールバックのルーティング、設定の変更】

sorcery ではクエリを渡す形でコールバックを設定しているが、

config.twitter.callback_url = "http://0.0.0.0:3000/oauth/callback?provider=twitter"

Twitter Developer 側 ではコールバックにクエリを含めることが出来ないため、クエリを入れないように変更。

 - 上記コールバック設定から「?provider=twitter」を削除
 - 削除したURLを、Twitter Developer のアプリ設定の「Callback URLs」
  へ設定
 - OauthsController の login_from(provider) で渡す provider 文字列を
  自前で入れる

【本番用のTwitterコールバックを追加】

Twitter 側からアプリ側へ戻るためのコールバックについて、開発時は「http://localhost:3000〜〜」へ飛ばすが、本番では本番用アプリのURLへ飛ばす必要があるため、下記手順で追加する。
(追加しないと、本番用アプリで実行した際に localhost:3000〜へアクセス
 してしまう)

 - Twitter Developer のアプリ設定の「Callback URLs」へ本番用アプリの
  URLを追加
 - sorcery.rb の callback_url を、環境毎に読み換えるよう実装する
  例)config の Gem を入れて環境毎に設定する

# config/settings/development.yml
twitter:
  callback_url: http://localhost:3000/users/auth/twitter/callback

# config/settings/production.yml
twitter:
  callback_url: https://<本番アプリのドメイン>/users/auth/twitter/callback
  

【Twitterのアカウント情報を取得する際の設定の追加】

設定を追加して sorcery 経由で取得する(Response 情報)。

- Twitter Developer ページのアプリ内「Keys and tokens」にある
「API key」と「API secret key」を、Rails5.2 で追加された
 Credentials を使って設定しておき、sorcery.rb で指定する

- 取得したいパラメータ(アカウント名など)を user_info_mapping で
 指定する。
 (ハッシュの key は任意の文字列、value は Twitter 側のパラメータ名)

# sorcery.rb

config.twitter.key = Rails.application.credentials.twitter[:key]
config.twitter.secret = Rails.application.credentials.twitter[:secret]
# 「本番用のTwitterコールバックを追加」で追加したURLを指定
config.twitter.callback_url = Settings.common.twitter.callback_url

config.twitter.user_info_mapping = {
  name: 'name',
  screen_name: 'screen_name',
  profile: 'description',
  profile_image_url: 'profile_image_url_https'
}

メールアドレスを取得する場合は追加で対応が必要になる。
Twitter Developer ページ>アプリ選択>App Details で
「Terms of service URL」「Privacy policy URL」を設定しておく
- 「Permissions」でメールアドレス取得を要求する
- sorcery の設定を追加する

# sorcery.rb

# email を追加
config.twitter.user_info_mapping = {
  name: 'name',
  screen_name: 'screen_name',
  profile: 'description',
  profile_image_url: 'profile_image_url_https',
  email: 'email'
}
config.twitter.user_info_path = "/1.1/account/verify_credentials.json?include_email=true"

参考:https://qiita.com/hayayuske/items/83bb48c2fdac803cc8f3

【連携キャンセルで 401 エラー】

sorcery の login_at() でアプリ連携しようとしてキャンセルして帰ってきたコールバック内で 401 エラーになる。

OAuth::Unauthorized (401 Authorization Required):

内部で denied パラメータ判定でリダイレクトして対応。

class Users::OauthsController < ApplicationController
  def callback
    redirect_to login_url and return if params[:denied].present?

    〜通常時の処理〜
  end
end

【連携を外す】

連携周りをテストする際、連携したり解除したい。
Twitter の設定画面の「アプリと端末」から連携の取り消しが出来る。


コールバック周りで苦戦しましたが、OauthsController.oauth() → Twitter → OauthsController.callback() の流れが見えると、どう設定すればいいのか掴めました。
また、Twitter のアバター画像をアプリ側で取得するのも自前でやれたので必要十分な連携かなと思います(長いので別記事に)。
登録周りがごちゃごちゃせず、開発側もユーザー側も便利になって良いですね。

この記事が気に入ったらサポートをしてみませんか?