LoginSignup
9
5

Sorceryで認証機能を実装してみた

Last updated at Posted at 2024-04-07

1.はじめに

RailsチュートリアルDeviseを使ったログイン機能の記事はよく見るけど、Sorceryの記事は比較的少ないと思ったので、この記事を書きました。

皆様の学習の一助になれれば幸いです🙏

目次
1. はじめに
2. 導入方法
3. ログイン機能の実装
4. 動作確認
5. 終わりに
6. 参考記事

開発環境
Ruby 3.2.3
Rails 7.1.3
Sorcery(gem)
jQuery 3.7.1

2. 導入方法

sorcery

sorceryの公式ドキュメントに沿って導入していきます。

.Gemfile
gem 'sorcery'

今回はログイン情報を記憶する機能も実装するため、remember_me を付与しています。

$ rails generate sorcery:install remember_me 

作成されたマイグレーションファイルは以下になります。

db/migrate/20240211071358_sorcery_core.rb
class SorceryCore < ActiveRecord::Migration[7.0]
  def change
    create_table :users do |t|
      t.string :email,            null: false, index: { unique: true }
      t.string :crypted_password
      t.string :salt

      t.timestamps                null: false
    end
  end
end
db/migrate/20240216115807_sorcery_remember_me.rb
class SorceryRememberMe < ActiveRecord::Migration[7.0]
  def change
    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
end
$ rails generate migration AddColumnUsers name:string
db/migrate/20240217004047_add_column_users.rb
class AddColumnUsers < ActiveRecord::Migration[7.0]
  def change
    add_column :users, :name, :string
  end
end

必要に応じて手動でカラムを追加してください。
上記の場合はnameカラムを追加しています。

config/initializers/sorcery.rb
Rails.application.config.sorcery.submodules = [:remember_me]

# Here you can configure each submodule's features.
Rails.application.config.sorcery.configure do |config|
  config.user_config do |user|
    user.stretches = 1 if Rails.env.test?
    user.remember_me_for = 180 #変更
    end
    config.user_class = "User"
end

remember_me_tokenの有効期限を設定します。
期限は例として180秒で動作確認用に設定しています。

jQuery

flashメッセージを実装するためにjQueryを導入します。
以下はjQueryのCDN最新バージョン(2024年4月時点)を読み込む方法です。
Rails7ではHotwire(Turbo)がデフォルトで実装されているため、そちらを使用しています。

app/views/layouts/application.html.erb
<html>
  <head>
    <title>minapp</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %>
    <script src="https://code.jquery.com/jquery-3.7.1.min.js"></script> <%#追加 %>
  </head>

    <body>
     <div>
      <% flash.each do |message_type, message| %>
        <div class="flash-message <%= message_type %>"><%= message %></div>
      <% end %>
     </div>
     <div id="nav">
      <% if logged_in? %>
        <%= link_to "ログアウト", logout_path, data: { turbo_method: :delete } %>
      <% else %>
        <%= link_to "新規登録", new_user_path %> |
        <%= link_to "ログイン", login_path %>
      <% end %>
    </div>
    <%= yield %>
  </body>
</html>

FlashメッセージのCSS

app/assets/stylesheets/application.css
.flash-message {
  border-radius: 5px;
  padding: 16px 24px;
  margin: 16px 0px;
}
 
.flash-message.notice {
  background-color: #bcdfff;
  color: #0067C0;
  border: solid 1px #0067C0;
}
 
.flash-message.alert {
  background-color: #ffd4d1;
  color: #930403;
  border: solid 1px #930403;
}
app/javascript/application.js
import $ from 'jquery';
import "jquery-ujs";
import "@hotwired/turbo-rails";
import "controllers";

$(function() {
  $('.flash-message').fadeOut(4000);
  console.log($('.flash-message'));
});
app/assets/config/manifest.js
//以下を追加
//= require jquery
//= require jquery_ujs
//= require_tree .

3. ログイン機能の実装

モデル

app/models/user.rb
class User < ApplicationRecord
  authenticates_with_sorcery!

  validates :email, uniqueness: true, presence: true
  validates :password, length: { minimum: 3 }, if: -> { new_record? || changes[:crypted_password] }
end

authenticates_with_sorcery!でsorceryの認証を有効にしています。

ルーティング

config/routes.rb
Rails.application.routes.draw do
  get 'login' => 'sessions#new', as: :login
  post 'login' => "sessions#create"
  delete 'logout' => 'sessions#destroy', as: :logout

  root to: "samples#index"

  resources :users, except: [:index]

end

コントローラー

app/controllers/sessions_controller.rb
class SessionsController < ApplicationController
  skip_before_action :require_login, only: [:new, :create]

  def create
    @user = login(params[:email], params[:password], params[:remember_me])

    if @user
      redirect_back_or_to(root_path, notice: 'ログインに成功しました')
    else
      flash.now[:alert] = 'ログインに失敗しました'
      render action: 'new'
    end
  end

  def new
    @user = User.new
  end

  def destroy
    remember_me!
    forget_me!
    logout
    redirect_to(login_path, notice: 'ログアウトしました')
  end
end

  • createアクションにてparams[:remember_me]を追加することで、ログイン時にremember_me_tokenを発行し、ログイン情報を記憶できます。
  • require_loginメソッドはloginしているかどうかを検証します。ログインを必要としないページには、このskip_before_actionを適用しています。
  • destroyアクションにて remember_me!forget_me!を追加することでログアウト前にremember_meトークンを削除しています。

ビュー

app/views/sessions/new.html.erb
<h1>ログイン</h1>

<%= form_with url: login_path, method: :post, data: { turbo: false } do |f| %>
  <div class="field">
    <%= f.label "メールアドレス" %><br />
    <%= f.text_field :email %>
  </div>
  <div class="field">
    <%= f.label "パスワード" %><br />
    <%= f.password_field :password %>
  </div>
  <div class="field">  
    <%= check_box_tag :remember_me, params[:remember_me], true %>  
    <%= label_tag :remember_me %>  
  </div>  
  <div class="actions">
    <%= f.submit "ログイン", data: { turbo: false } %>
  </div>
<% end %>

<%= link_to 'トップページへ戻る', root_path, data: { turbo: false } %>

ログインページのビューです。
remember_meのチェックボックスを追加しています(デフォルトでTrueにしています)

4. 動作確認

  1. http://localhost:3000/login でブラウザにアクセスします。
  2. デベロッパーツールを開く。
  3. メールアドレス、パスワード、remember_meのチェックボックスをONにしてログインする。
  4. ログイン成功し、Flashメッセージが表示される。この時、デベロッパーツールの「アプリケーションタブ」のCookie内を確認すると、session情報とremember_meトークンが発行されます。
  5. ログアウトする

sorcery.gif

5. 終わりに

  • deviseは機能が豊富な反面、カスタマイズするためにはdevise内部の機能を追う必要があり、苦労しました。
  • 対してsorceryは軽量で必要最低限の実装で実現できました。比較的シンプルにコードが書けて、認証に関する知識が必要になるものの、カスタマイズはdeviseよりも柔軟に行いやすいという印象でした。
  • どちらもメリットデメリットがあり、プロジェクトに応じてライブラリを選定することが大事だと思いました。

6. 参考記事

Sorcery(公式ドキュメント)
[Ruby on Rails]sorceryによる認証 – (2)ユーザ名による認証とRemember-Me
devise(公式ドキュメント)

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