Rails でアカウントロジックを扱うなら sorcery が良いかも

  • 18
    いいね
  • 0
    コメント
この記事は最終更新日から1年以上が経過しています。

導入文

Rails でアカウントロジック(ユーザ認証やSNSログイン)を扱いたい場合、大体 device を使うというのが定石っぽい風潮であるように思われるのですが、ある程度アカウントロジックにかかわる機能を自分で自由に扱いたい場合は sorcery を使うとシンプルに出来るんじゃないだろうか、と思って試した結果、結構シンプルに扱えたので良かったという内容です。

公式サイト

https://github.com/NoamB/sorcery

です。device で四苦八苦した経験をお持ちの方であれば、README.md や wiki をざっと読むだけで扱えるかと思います。

インストール

最低限必要なファイルについては rails generate sorcery:install で生成されます。

console
$ cd /path/to/your-awesome-rails-app/
$ echo "gem 'sorcery', '~> 0.9.1'" >> Gemfile
$ bundle install
$ bundle exec rails generate sorcery:install

共通設定+SNSログイン設定

sorcery に関する設定は config/initializers/sorcery.rb に記述します。 device で SNS ログインを扱う場合 omniauth を併用する必要がありますが、sorcery の場合は sorcery だけで完結できてシンプルです。

Rails.application.config.sorcery.submodules には、本来のアカウントロジックに加えて扱いたい機能を列挙することができます。記事執筆時点でデフォルトとして揃っているのは

  • Eメールによるユーザアクティベーション (:user_activation)
  • HTTP ベーシック認証 (:http_basic_auth)
  • ログイン状態の維持 (:remember_me)
  • パスワードを忘れた場合の再設定 (:reset_password)
  • セッションタイムアウト (:session_timeout)
  • ブルートフォース防御 (:brute_force_protection)
  • 最後にログインしたのはいつか、などアカウントアクティビティの記録 (:activity_logging)
  • 外部サイト認証 (:external)

です。「あの機能が使いたいのに!」というのはほぼ揃っている感じですね。

下記は「twitterとfacebookのログイン機能を使いたい場合」の設定例です。必要値は適時準備してください。

config/initializers/sorcery.rb
# 扱いたい機能
Rails.application.config.sorcery.submodules = [:external]
Rails.application.config.sorcery.configure do |config|
  # 対応するプロバイダ
  config.external_providers = [:twitter, :facebook]
  # Twitter 固有の設定
  config.twitter.key = ENV["CONFIG_TWITTER_KEY"]
  config.twitter.secret = ENV["CONFIG_TWITTER_SECRET"]
  config.twitter.callback_url = ENV["CONFIG_TWITTER_CALLBACK_URL"]
  config.twitter.user_info_mapping = { name: "screen_name", sns_icon_image: "profile_image_url_https" }
  # Facebook 固有の設定
  config.facebook.key = ENV["CONFIG_FACEBOOK_KEY"]
  config.facebook.secret = ENV["CONFIG_FACEBOOK_SECRET"]
  config.facebook.callback_url = ENV["CONFIG_FACEBOOK_CALLBACK_URL"]
  config.facebook.user_info_mapping = { email: "email", name: "name", sns_icon_image: "picture/data/url" }
  config.facebook.user_info_path = "me?fields=email,name,picture"
  config.facebook.access_permissions = ["public_profile", "user_about_me", "email"]
  config.facebook.scope = "public_profile,user_about_me,email"
  config.facebook.display = "page"
  config.facebook.api_version = "v2.5"
  # ユーザモデルに関する設定
  config.user_config do |user|
    # 外部サイト認証に関するデータを扱うモデル
    user.authentications_class = Authentication
  end
  # ユーザモデルをどのクラスで扱うか
  config.user_class = "User"
end

twitter や Facebook 以外の外部サイト認証についても対応されています。詳しくはこちらでご確認下さい。

モデルについて

モデルは基本設定を特に変更しなければ、device と同様 User モデルを扱う形になります。

パスワードの検証はデフォルトで「同じパスワードを2回入力し、合致するかどうかを検証する」方式になっています。バリデーションの if では

  • ユーザー新規登録時か (new_record?)
  • 既存パスワードを変更する場合か (changes[:crypted_password])

がチェックされています。

app/models/user.rb
class User < ActiveRecord::Base
  authenticates_with_sorcery! do |config|
    config.authentications_class = Authentication
  end
  accepts_nested_attributes_for :authentications
  validates :password, presence: true, length: { minimum: 8 }, if: -> { new_record? || changes[:crypted_password] }
  validates :password, confirmation: true, if: -> { new_record? || changes[:crypted_password] }
  validates :password_confirmation, presence: true, if: -> { new_record? || changes[:crypted_password] }
end

routes.rb について

ルーティングは以下のような形になります。外部サイト認証の場合 /oauth/* が必要となるので、追記します。

config/routes.rb
  resources :user_sessions
  resources :users
  get 'login' => 'user_sessions#new', as: :login
  get 'logout' => 'user_sessions#destroy', as: :logout
  get 'oauths/oauth'
  get 'oauths/callback'
  post "oauth/callback" => "oauths#callback"
  get "oauth/callback" => "oauths#callback"
  get "oauth/:provider" => "oauths#oauth", as: :auth_at_provider

コントローラとビューについて

ユーザの新規作成や編集、削除(退会)については users_controller.rb で、ログイン・ログアウトについては user_sessions_controller.rb で、外部サイト認証は oauths_controller.rb で扱う形です。

ビューについては device でお馴染みのヘルパメソッド current_user を用いて、似たようなロジックを使うことができます。

公式ドキュメント(wiki)では以下の箇所が参考になります。基本的には書いてあるコードサンプルを順番に作っていけばそれでいいような感じになっており、なかなかシンプルです。

device と比べてどこが良いのか

device ではある程度定められたアカウントロジックが提供されるものの、その「ある程度定められたアカウントロジック」を少しカスタマイズしたいなどと言った場合(内容にもよりますが)途端にメンテナンスが難しくなります。

これに対する sorcery のアプローチは「必要なものはあるから適時作成したりしなかったりして欲しい」というようなものになるかと思います。device がフルスタックであるのに対し、sorcery はアカウントロジックの一挙一動(どこで何を実行するか)を自分で記述しなければならない手間はあるものの「書いたものだけが動く」という点においてはシンプルであり、そのような視点においては device よりも見通しの良いアカウントロジックを構築することができます。

なので「gem をインストールして rails generate sorcery:install すればコントローラもビューもモデルもバババーンと揃ってスパパパーンと動いてイージー」ということにはならないため、そういう意味での面倒臭さはありますが、メンテナンス性などを考慮するのであれば、利用する価値は十分あるのではないかと感じました。

device をある程度経験した方であればすんなり学習可能な gem だと思います。

※ 個人的には外部サイト認証を利用する際に omniauth など複数の gem を定義しなくてもよい点が好きです