TUNAGのログイン認証を支えるgem deviseの話

こんにちは。スタメンエンジニアの松川です。
今回は、前回、市川の方からスタメンの開発コンセプトにあげられた

・ツールやライブラリをちゃんと使いこなす

に着目したいと思います。

前回、紹介があった通り、スタメンではアプリケーションフレームワークとして、Ruby on Railsをメインに使用しています。
スタメンでは、「少ない人数で いかに(ラクをして)サービスの開発に注力するか」という観点の元、ライブラリとして複数のgemを活用して開発を行なっています。

gem

gemとは、サードパーティ製のライブラリのことです。日本語では”宝石”を意味しており、数々の宝石のように優れたオープンソースのライブラリがこの世には存在しています。

主に活用しているgem

スタメンでは、様々な場面でお世話になっているgemがあります。ログイン、非同期処理、Modelの状態遷移、decoratorなど自分達で実装するのは、実装工数が多く、共通化されたgemを使用すると恩恵が生まれやすい部分に活用しています。

ログイン部分では、Railsでログイン認証周りの管理を簡単に実装できるメジャーgemであるdevise
非同期処理部分ではdelayed_job、Modelの状態遷移ではaasm、decoratorではdraperをそれぞれ使用しています。

今回は、ログインに使用しているdeviseを取り上げて、ご紹介したいと思います。
https://github.com/plataformatec/devise

deviseに全く触れたことがないという方やdeviseを試しに入れてみたのだけど使い方、全体像がよく分からないという方を対象にしていますので、概略の説明になっています。deviseのモジュールの中身の話については、次回以降、機会があればご紹介出来ればと思います。

devise

Railsでログイン認証周りの管理を簡単に実装できるメジャーgem

gem 'devise'

スタメンとして、deviseを導入した経緯としては、スタメンが運用しているTUNAGというサービスが、複数の役割を持ったユーザーのログインを想定したプロダクトであったためです。deviseは、wardenというシステムを元にして開発されたgemであり、複数の役割を持ったユーザーのセッション管理を容易にする機能を持っています。

例として、下記のような役割が別れたユーザーのログインを想定したサービスの場合、deviseの力が発揮されます。

ControllerやViewの内部で、

current_user
user_signed_in?
current_admin_user
admin_user_signed_in?

のようなhelperメソッドでセッションを複数保持した場合でもログイン状態のユーザーを個別に参照できるため、ログイン管理の煩雑さから解放されます。ログインユーザー個別の情報にアクセスしたい場合でも、

current_user.feeds
current_user.reports

などのassociationで辿れるため、可読性&安全性が高まります。

構成モジュール

 deviseは、10個のモジュールにより構成されており、それぞれが異なる機能を提供しています。
 それぞれの機能は、Modelに下記のような形で設定することでON、OFFを管理することが可能なため、非常に便利です。

devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
  • database_authenticatable(パスワードの暗号化など)
  • registerable(サインイン処理)
  • recoverable(パスワード再設定)
  • rememberable(セッション期間の延長)
  • trackable(サインイン回数やサインイン時間、IPアドレスの記録)
  • validatable(パスワードやメールアドレスの登録検証)
  • confirmable(アカウントの認証)
  • lockable(アカウントのロック)
  • timeoutable(セッションの時間管理)
  • omniauthable(外部サービス認証)

 deviseをフルに活用すると、下の図のような登録フローやパスワードの再設定フロー、アカウントのロック機能などを実装することが可能です。例えば、パスワード認証を許可せずに外部サービス認証のみ許可するということもdeviseを使用することで可能となります。

ログイン管理をしたいModel(User、Customer etc)が決定したら、

rails generate devise User

上記のコマンドによって、deviseの認証に使用するmodelとDBのカラム(migrationファイル)が自動生成されます。

# == Schema Information
#
# Table name: users
#
#  id                     :integer          not null, primary key
#  email                  :string(255)      default(""), not null
#  encrypted_password     :string(255)      default(""), not null
#  reset_password_token   :string(255)
#  reset_password_sent_at :datetime
#  remember_created_at    :datetime
#  sign_in_count          :integer          default(0), not null
#  current_sign_in_at     :datetime
#  last_sign_in_at        :datetime
#  current_sign_in_ip     :string(255)
#  last_sign_in_ip        :string(255)
#  created_at             :datetime         not null
#  updated_at             :datetime         not null
#

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable

の表記で活用する機能の取捨選択が可能となります。ただし、導入する機能によっては、新たにカラムを追加する必要があるものやカラムを追加していない場合には、代替のカラムで機能が実現されている可能性があるため、注意してください。

 deviseの実際の実装方法については、公式ドキュメントやqiitaの解説記事に詳細が載っていますので、割愛しますが、deviseの利点は、カスタマイズ性の容易さも挙げられます。認証機能を実現しているDevise::SessionControllerのメソッドをオーバーライドすることにより、ログイン画面で表示させたい情報やログイン後にやっておきたい同期・非同期処理を組み込むことも容易に可能です。

class Users::SessionsController < Devise::SessionsController
   def new
    super
   end

   def create
    super do |user|
        # add some process
    end
  end
end

 また、外部サービスを使用した認証の場合でも上記のControllerに認証アクションをまとめておくことで、コードの見通しも良くなります。

 その他にもdeviseで標準で用意されているメールテンプレートやログイン・パスワード設定画面なども独自にカスタマイズすることが可能なため、基幹部分のロジックを崩すことなくサービスに合わせた形で認証機能を実現することが可能となります。

 この基幹部分を崩すことなく、様々なカスタマイズが可能な点が多くのWebサービスにこのdeviseが採用されている意味だと感じます。

deviseと連携可能なgem

 TUNAGでは使用していませんが、deviseは外部サービスとのOAuth認証のためのgemが数多く公開されています。
TwitterアカウントやFacebookアカウントを使用してサービスにログインさせたい場合でも、公開されているgemを使用してログイン実装することが可能です。

gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'omniauth-twitter'

終わりに

 今回は、ログイン部分に使用しているgem deviseについて紹介しました。優れたgemを使いこなすことで、サービスの開発効率や品質を向上することが出来ます。その他にも、サービスを開発するにあたり、様々なgemを活用して開発の効率化をしています。

 次回以降、deviseの詳細なモジュールの中身の話や様々な認証方式(SAML認証やOpenID Connect)についても紹介していきたいと思っています。

  • スタメンでは一緒に働くメンバーも募集しております!是非ご覧ください。

スタメンの採用情報