LoginSignup
5
6

More than 5 years have passed since last update.

1つのモデルで複数プロバイダに対応(AuthlogicとOmniAuthの話の続き)

Last updated at Posted at 2014-10-27

AuthlogicとOmniAuthを使って複数のアカウントと連携するで、

例えば、ここから Twitter アカウントでも認証させたくなったら。
FacebookAccount と同じ要領で追加すれば良いだけなので以下略。

とか書いたのだけれども、対応プロバイダ増やす度にモデル作るの面倒だなって思ったので、いっこのモデルで複数プロバイダ対応できるようにしたよ。
という話。

これまでのあらすじ

  • 1 User に対して、複数の認証方法(FacebookやTwitterなど)でログインさせたかった
  • devise を諦めて Authlogic 使うことにした
  • Authlogic の add on は使わず、対応サービスも豊富な OmniAuth 使うことにした

gem の導入なんかは前回の記事でできている前提。

本題:対応プロバイダ増やすたびにモデル作るの面倒だね

各サービス毎の差異は OmniAuth がうまいことラッピングしてくれるので、単一モデルでもいける気がしたのでやってみた。

コントローラからは Account.authenticate(env['omniauth.auth']) で呼び出す。

app/models/user.rb
class User < ActiveRecord::Base
  acts_as_authentic

  has_many :accounts
end
app/models/account.rb
class Account < ActiveRecord::Base
  belongs_to :user

  scope :by, ->(provider) { where(provider: provider) }
  scope :by_uid, ->(provider, uid) { by(provider).where(uid: uid) }

  # 認証情報からアカウントを用意する
  #
  # @param [AuthHash] auth
  #   see https://github.com/intridea/omniauth/wiki/Auth-Hash-Schema
  # @return [Account] 認証したアカウント情報
  #   この時点ではまだsaveされていない
  def self.authenticate(auth)
    account = by_uid(auth.provider, auth.uid).first_or_initialize

    account.attributes = {
      token: auth.credentials.token,
      secret: auth.credentials.secret,
      nickname: auth.info.nickname,
      name: auth.info.name,
      image_url: auth.info.image,
      profile_url: auth.info.urls.fetch(auth.provider.to_s.camelize),
    }

    if auth.credentials.expires_at
      account.expires_at = Time.zone.at(auth.credentials.expires_at)
    end

    account
  end

前回の記事では、このメソッド内で User.create までやっていたのだけれども、今回それはやめてた。
なので、呼び出した側で user についての処理をよしなにした上で save する必要がある。

これは新規登録とかログインとか連携追加とかの対応のための変更。
そもそもの目的だった「1Userにつき複数アカウント」という状態にするために必要だったんだけど、それはそれで長くなるので、今回は書かない(力尽きた)。

そうしたら、後は各プロバイダのアプリ設定さえしてしまえば、対応プロバイダは割と楽に増やしていけそうな予感。

config/initializers/omniauth_builder.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :facebook,
    Rails.application.secrets.facebook_app_id,
    Rails.application.secrets.facebook_app_secret
  provider :twitter,
    Rails.application.secrets.twitter_api_key,
    Rails.application.secrets.twitter_api_secret,
    {
      image_size: 'bigger',
    }
end

Omniauth がラッピングしてくれてるとはいえ、各プロバイダ毎に取得できる項目できない項目、どんな値が入って来るか、など結構ばらばらなので気を付ける必要はある。

5
6
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
5
6