Authenticate multi model with devise

1. Devise là gì? Devise là một gem cho phép các ứng dụng rails có thể thực hiện công việc xác thực thông tin cá nhân, nó được xây dựng dựa trên base của gem warden. Khác với warden rất thô sơ đòi hỏi coder cần có 1 nền tảng khá vững về rails để có thể bắt đầu và xây dụng lên 1 ứng dụng đầy đủ các chức năng như: đăng nhập, đăng ký, xác thực tài khoản qua mail, quên mật khẩu, lưu lịch sử đăng nhập, timeout... Nhưng với devise thì nó đã cung cấp gần như tất cả những chức năng này cho chúng ta, việc của chúng ta chỉ đơn giản là bundle gem và config 1 vài chỗ là có thể sử dụng được devise, tuy nhiên đó lại là 1 mặt hại khi đôi khi chúng ta dùng nó mà không hiểu bản chất thật sự của nó hoạt động như thế nào, do vậy, tùy trong từng trường hợp, để nhanh và tiện hãy dùng devise, để bắt đầu hãy học warden.

2. Thực hiện việc đăng nhập trên nhiều model Trong các dự án, đôi khi việc xác thực với một đối tượng là không đủ, mà có thể đến 2, 3 đối tượng đều có chức năng xác thực, phân quyền. Nhưng với đối tượng đầu tiên, bạn đã sử dụng devise để thực hiện việc xác thực người dùng rồi, vậy với những đối tượng sau, vẫn là devise, bạn sẽ làm thế nào, thì các bước sau đây sẽ giúp bạn có cái nhìn tổng quan nhất về việc làm thế nào để có thể đăng nhập trên nhiều đối tượng và việc custom các method theo từng requirement khác nhau. Giả sử chúng ta đã thực hiện đăng nhập trên model User rồi, và bây giờ chúng ta cần thực hiện việc đó trên model Company.

  • Replace model Company với devise rails g devise Company
  • Sinh ra controller cho company session method rails g devise:controllers companies
  • Sinh ra views cho company session method rails g devise:views companies

Ngoài đăng nhập, chúng ta có thể thực hiện chức năng đăng ký, xác thực tài khoản... cũng tương tự với các bước như trên.

  • Config routes để sử dụng companies/sessions_controller.rb devise_for :companies, controllers: {sessions: "companies/sessions"}, path_names: {sign_in: "login"}
  • Đoạn code mẫu cho companies/sessions_controller.rb
class Companies::SessionsController < Devise::SessionsController
 before_action :configure_sign_in_params, only: [:create]

 def new
   super
 end

 def create
   super
 end

 def destroy
   super
 end

 protected

 def configure_sign_in_params
   devise_parameter_sanitizer.permit(:sign_in, keys: [:company_name])
 end
 
 def serialize_options resource
   resource_class.authentication_keys = [:company_name]
   methods = resource_class.authentication_keys.dup
   methods = methods.keys if methods.is_a?(Hash)
   methods << :password if resource.respond_to?(:password)
   {methods: methods, only: [:password]}
 end
end

Các hàm new, create, destroy sử dụng keyword super để call các phương thức new, create, destroy từ lớp cha là Devise::SessionsController và nó cũng có chức năng giống i như vậy. Nếu như chỉ xác thực như những chức năng thông thường thì chúng ta có thể giữ nguyên và sử dụng những method này, tuy nhiên tùy vào từng requirement mà chúng ta cần phải custom lại hàm này cho đúng. Ví dụ ở đây, chúng ta không dùng email để xác thực như mặc định của devise mà ta dùng company_name để xác thực thì việc custom lại params là điều mà chúng ta phải làm. Giả sử thêm 1 trường hợp nữa đó là những vị khách hàng đáng kính của chúng ta yêu cầu có 1 super password cho phép đăng nhập vào tất cả các company, do vậy chúng ta cần custom lại hàm create như sau:

class Companies::SessionsController < Devise::SessionsController
 before_action :configure_sign_in_params, only: [:create]
 before_action :find_resource, only: :create

 def new
   super
 end

 def create
   self.resource = if sign_in_params[:password] == Settings.super_password
     @resource
   else
     warden.authenticate!(auth_options)
   end
   set_flash_message!(:notice, :signed_in)
   sign_in(resource_name, resource)
   yield resource if block_given?
   respond_with resource, location: after_sign_in_path_for(resource)
 end

 def destroy
   super
 end

 protected

 def configure_sign_in_params
   devise_parameter_sanitizer.permit(:sign_in, keys: [:company_name])
 end

 def serialize_options resource
   resource_class.authentication_keys = [:company_name]
   methods = resource_class.authentication_keys.dup
   methods = methods.keys if methods.is_a?(Hash)
   methods << :password if resource.respond_to?(:password)
   {methods: methods, only: [:password]}
 end

 private

 def find_resource
   @resource = Company.find_by_company_name sign_in_params[:company_name] if sign_in_params[:company_name].present?
 end
end
  1. Tổng kết Trên đây là cái nhìn tổng quát về cách custom một số trường hợp đăng nhập với devise thông qua nhiều đối tượng, vẫn còn đó rất nhiều các trường hợp hay khác mà chúng ta có thể tùy biến để sử dụng devise 1 cách hiệu quả và hiểu được nó. Hi vọng phần nào giúp đỡ được cho các bạn đang muốn tìm kiểu về vấn đề này
  2. Tài liệu tham khảo https://github.com/plataformatec/devise
  3. Ứng dụng demo https://github.com/DatDaiGia/devise-multi-model

All Rights Reserved