[Ruby on Rails]sorceryによる認証 – (2)ユーザ名による認証とRemember-Me

2015.04.30

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

前回に引き続きsorceryによる認証についてです。今回はユーザ名のよる認証と、Remember-Me機能の実装を行ってみました。

実装手順

前回と同様、基本的には公式サイトのチュートリアルに沿って実装しました。ですがチュートリアルではメールアドレスを使用しているので、これをユーザ名に変えることと、Remember-Me機能の追加を独自に行っています。以下、その手順です。メモを元に書いているので漏れ等あったら、すいませんw。

1.プロジェクトの作成〜sorceryのインストール

これらの手段は前回やチュートリアルと同様です。Gemfileへの記述と、コマンドだけ載せておきます。

Gemfile
gem 'sorcery'
$ bundle install --path vendor/bundle
$ rails g sorcery:install

2.Remember-Meの追加

以下のコマンドを実行後、サブモジュールとして「remember-me」を取り込むよう定義ファイルに記述します。またタイムアウトの期間を設定します(ここでは2週間を秒単位で保持しています)。

$ rails g sorcery:install remember_me --migrations
config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:remember_me]
(中略)
config.user_config do |user|
  (中略)
  user.remember_me_for = 1209600 # Two weeks in seconds
  (中略)
end

3.ユーザ名を使用することの定義

sorceryはデフォルトではメールアドレスでユーザーを特定するようになっているため、ユーザ名を使用するよう定義ファイルを変更します。

config/initializers/sorcery.rb
user.username_attribute_names = [:username]

次にUserテーブルにも「email」ではなく「username」を保持するよう、migrationファイルを変更します。

db/migrate/作成日時_sorcery_core.rb
t.string :username,            :null => false

4.Remember-MeをUserテーブルに追加

Userテーブルに「remember-me」を保持するよう、migrationファイルを追加します。

db/migrate/作成日時_add_rememver_me_users.rb
class AddRememverMeUsers < ActiveRecord::Migration
  def self.up
    add_column :users, :remember_me_token, :string, :default => nil
    add_column :users, :remember_me_token_expires_at, :datetime, :default => nil

    add_index :users, :remember_me_token
  end

  def self.down
    remove_index :users, :remember_me_token

    remove_column :users, :remember_me_token_expires_at
    remove_column :users, :remember_me_token
  end
end

ここでmigrateを実行します。

$ rake db:migrate

5.Userのスキャフォールド

スキャフォールドを行いますが、ここも「email」ではなく「username」を使用するようにします。

$ rails g scaffold user username:string crypted_password:string salt:string --migration false

ユーザコントローラにて、ユーザ名やremember-meを受け取れるように以下のメソッドを追加します。

app/controllers/users_controller.rb
def user_params
  params.require(:user).permit(:username, :password, :password_confirmation, :remember_me)
end

パスワードの入力欄を作成します。

app/views/users/_form.html.erb
<div class="field">
   <%= f.label :password %><br />
   <%= f.password_field :password %>
</div>
<div class="field">
   <%= f.label :password_confirmation %><br />
   <%= f.password_field :password_confirmation %>
</div>

ユーザモデルを編集します。

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

  validates :password, length: { minimum: 3 }
  validates :password, confirmation: true
  validates :password_confirmation, presence: true

  validates :username, uniqueness: true
end
[/ruby]
</p>
<h3>6.以降の手順</h3>
<p>
以降の手順については、<a href="https://github.com/NoamB/sorcery/wiki/Simple-Password-Authentication" target="_blank" rel="noopener noreferrer">チュートリアル</a>にて「UserSessions」コントローラを作成するところ以降とほぼ同じです。チュートリアルの以下のコマンド以降になります。

今回変えたのは以下の箇所です。
</p>
<p>
<h5>app/controllers/user_sessions_controller.rb</h5>

  def create
    if @user = login(params[:username], params[:password], params[:remember])
      redirect_back_or_to(:users, notice: 'Login successful')
    else
      flash.now[:alert] = 'Login failed'
      render action: 'new'
    end
  end

  def destroy
    remember_me!
    forget_me!
    logout
    redirect_to(:users, notice: 'Logged out!')
  end

「email」を「username」に変えています。また「destroy」アクションにてlogoutする前に「remember_me!」「forget_me!」を追加しています。これによりログアウト時にユーザのセッション情報を消すことが出来るようになります。

/app/views/user_sessions/_form.html.erb
<%= form_tag user_sessions_path, :method => :post do %>
  <div class="field">
    <%= label_tag :username %><br />
    <%= text_field_tag :username %>
  </div>
  <div class="field">
    <%= label_tag :password %><br />
    <%= password_field_tag :password %>
  </div>
  <div class="field">  
    <%= check_box_tag :remember_me, 1, params[:remember_me] %>  
    <%= label_tag :remember_me %>  
  </div>  
  <div class="actions">
    <%= submit_tag "Login" %>
  </div>
<% end %>

こちらも「email」を「username」に変えています。また「remember_me」のチェックボックスを追加しています。

まとめ

sorceryの用意されている機能を元に、ユーザ名での認証・Remember-Meの実装を行うことができました。Remember-Meを実現するのに必要なサブモジュールを取り込みましたが、この必要に応じてモジュールを取り込むというのはsorceryの特徴の一つかと思います。

参考サイト

公式チュートリアル
Remember Me