Rails + devise + omniauth + devise_invitation で認証管理

こんにちは,池田(ゆ)です.

今回は,Ruby on Rails で作っている Web アプリケーションの認証管理をについて備忘録を残したいと思います.

やりたいことは,

  • アカウント作成をメールよる招待制にしたい
  • Google アカウント (OAuth) で認証したい

です!

内輪の Web サービスの認証情報管理を Google (OAuth) に任せたいのですが,誰でもログインできるようにはしたくないので,アカウント作成自体は,メールによる招待制にします.

招待制にすることによって,管理者ユーザが都度アカウントを作る面倒もないので,小さなユルいグループで運用するには便利そうです.

イメージは,こんな感じです.

  1. 内輪サービスにログイン済みのユーザAさんが,招待機能を使ってメールを送る
  2. メールを受け取った Bさんは,メール中のリンクをクリックすることで,Google の認証に飛ばされる
  3. 自分の好きな Google のアカウントで認証し,内輪サービスに認証結果を渡す許可を出す
  4. 内輪サービスに戻って来て,認証済みであることを確認する
  5. 内輪サービスのユーザ名登録に進む

ここで,招待状を送る相手Bさんのメールアドレスは,必ずしも Google アカウントのメールアドレスである必要ありません.

4つの gem を利用してこれを実現したため,その方法をまとめます.

今回は,すでに存在する Rails プロジェクトに認証管理を追加することが目的なため,
Rails プロジェクトの土台は出来上がっていることを想定しています.

利用する gem


今回利用する gem はこの4つです.

  • devise

    アプリケーションの認証に必要な機能を提供

  • omniauth

    複数のプロバイダを通してログイン認証ができる機能を提供

  • omniauth-google-outh2

    omniauth にて Google認証 を行うための gem

  • devise_invitable

    devise を使った招待機能を実現するための gem

Gemfileに以下を追記し,

gem "devise"
gem 'omniauth'
gem 'omniauth-google-oauth2'
gem 'devise_invitable'

以下のコマンドを実行し,gem をインストールしてください.

$ bundle install

devise の導入と利用


1. devise の設定

次に,以下のコマンドを実行して devise をインストールします.

$ bundle exec rails generate devise:install

さらに,デフォルト URL の設定として,config/environments/development.rb (production の場合は production.rb) に下記の行を追加します.

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

この設定で,招待メールに含まれる URL のホスト部分を変更できます.production の場合は,運用サイトのホスト名になります.

これで devise の導入は完了です!

2. モデルの生成

次に,devise を適用するモデル (User Model) を生成します.
User モデルは,既に存在していても構いません.

以下のコマンドを実行し User Model を生成します

$ bundle exec rails generate devise user
$ bundle exec rake db:migrate

生成されたマイグレーションファイルを見るとわかりますが,
devise で利用する用のカラムがたくさん追加されています!

次に,生成されたapp/models/user.rbを見るとこんな感じになっています.

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
            :recoverable, :rememberable, :trackable, :validatable
end

devise では10個のモジュールが定義されていて,使いたいものをapp/models/user.rbに追加することでモジュールを利用できるようになります.

デフォルトでは,database_authenticatableregisterableなど6個のモジュールが使えるようになっています.

使えるモジュールとそれぞれの内容については,deviseのGitHub を参照してください.

これで devise の導入は完了です!

3. リンクの設置と view の生成

app/views/layouts/application.html.erbに「Sign up」,「Sign in」,「Sign out」のリンクを設置します.

<% if user_signed_in? %>
  <%= link_to "Sign out", destroy_user_session_path, method: :delete, :class => "navbar-link" %>
<% else %>
  <%= link_to "Sign up", new_user_registration_path, :class => 'navbar-link' %> |
  <%= link_to "Sign in", new_user_session_path, :class => 'navbar-link' %>
<% end %>

user_signed_in?は devise の helper メソッドです.これにより,サインインしているか否かを判断できます.

ここで,アプリケーションの root が設定されていることを確認しておいてください.
devise ではサインインした後にはアプリケーションの root にリダイレクトするようになっているので,
root が設定されていないとエラーになってしまいます.

config/routes.rb に以下のような記述があると OK です.

Rails.application.routes.draw do
  root :to => "welcome#index"
  ...

サインイン画面などの view は devise が提供してくれます.

もし見た目が気に入らない!みたいな場合は, まず以下のコマンドを実行し view を生成します.

$ bundle exec rails generate devise:views

これにより,app/views/users/以下に以下の view が生成されるので,これを編集します.

  • ログイン app/views/devise/sessions/new.html.erb
  • ユーザー登録 app/views/devise/registrations/new.html.erb
  • ユーザ情報変更 app/views/devise/registrations/edit.html.erb
  • パスワード変更 app/views/devise/passwords/edit.html.erb
  • メール認証 app/views/devise/confirmations/new.html.erb
  • パスワードリセット app/views/devise/passwords/new.html.erb
  • アカウントアンロック app/views/devise/unlocks/new.html.erb

4. controller の生成

view と同様に,devise は controller も提供してくれています.

独自のメソッドやロジックを考慮したい場合は,view と同様に controller も生成します.

$ bundle exec rails generate devise:controllers users

これにより,app/controllers/users/以下に controller が生成されます.

controller を生成するときは,生成した controller を見るように,ルーティングを変更する必要があります.

devise_for :users, controllers: {
  registrations: 'users/registrations',
  confirmations: 'users/confirmations',
  passwords: 'users/passwords',
  sessions: 'users/sessions',
  unlocks: 'users/unlocks',
  omniauth_callbacks: "users/omniauth_callbacks"
}

omniauth の導入


1. omniauth を有効化

以下のコマンドを実行し,

$ bundle exec rails g migration add_omniauth_to_users

生成されたマイグレーションファイルに User Model に omniauth に必要なカラムを追加します.

class AddOmniauthToUsers < ActiveRecord::Migration
  def change
    add_column :users, :provider, :string
    add_column :users, :uid, :string
    add_column :users, :name, :string
    add_column :users, :token, :string
  end
end

その後に以下のコマンドを実行して,マイグレーションを完了させます.

$ bundle exec rake db:migrate

次に,app/models/user.rb:omniauthableを追加し,omniauth を有効にします.

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, and :timeoutable
  devise :database_authenticatable, :registerable,
            :recoverable, :rememberable, :trackable, :validatable, :omniauthable
end

2. Google Oauthの設定

まず, Google Console にアクセスし,アプリケーションのClient IDClient Secretを取得してください.

次に,config/initializers/devise.rbに取得したClient IDClient Secretを記述します.

config.omniauth :google_oauth2,
                         'Client_ID',
                         'Client Secret'

3. リンクの設置

app/views/layouts/application.html.erbに「Sign in with Google」のリンクを設置します.

<%= link_to 'Sign in with Google', omniauth_authorize_path(:user, :google_oauth2) %>

4. callback の記述

Google認証をし,アプリケーションに帰ってきたときのメソッドを記述する必要があります.

今回は,Google Console に以下のように callback を記述したことを想定します.

http://localhost:3000/users/auth/google_oauth2/callback

次に,app/controllers/users/omniauth_callbacks_controller.rbに callback 時に実行するメソッドを定義します.

def google_oauth2
  auth = request.env["omniauth.auth"]  if invitation_token != nil
  user = User.where(email: auth.info.email).first

  if user
    sign_in_and_redirect user, :event => :authentication
  else
    flash[:error] = "Your google account has not been registered"
    redirect_to  root_path
  end
end

devise_invitation の導入


1. devise_invitable のインストール

まず,以下のコマンドを実行します.

$ bundle exec rails g devise_invitable:install

次に,以下のコマンドを実行し,User Model に invitation に必要なカラムを追加します.

$ bundle exec rails g devise_invitable User
$ bundle exec rake db:migrate

さらに,app/models/user.rb:invitable を追加し,devise_invitation を有効化します.

class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, and :timeoutable
  devise :database_authenticatable, :registerable,
            :recoverable, :rememberable, :trackable, :validatable, :omniauthable, :invitable
end

2. controller の生成

devise_invitation には controller を自動生成するコマンドはないため,app/controllers/users/invitations_controller.rbを作ります.

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

  def create
     super
  end

  def edit
     super
  end

  def update
     super
  end

  def destroy
     super
  end
end

3. routing の設定

先ほど作成した controller への routing をconfig/routes.rbに追加します.

devise_for :users, controllers: {
  registrations: 'users/registrations',
  confirmations: 'users/confirmations',
  passwords: 'users/passwords',
  sessions: 'users/sessions',
  unlocks: 'users/unlocks',
  omniauth_callbacks: "users/omniauth_callbacks"
  invitations: 'users/invitations'    #追記
}

参考にしたWebページ



Comment

No comment