0

Cách sử dụng gem "devise"

Giới thiệu vấn đề Hôm nay mình xin giới thiệu tới các bạn một gem trong Ruby on Rails mà được rất nhiều lập trình viên Rails sử dụng, đó là gem devise Devise là một gem rất linh hoạt được sử trong quá trình xác thực người dùng. Nó hỗ trợ hầu hết tất cả mọi việc bạn cần trong việc quản lí và xác thực người dùng trong hệ thống của bạn. Nó được sử dụng rộng rãi hầu hết ở mọi project.

Tổng quan về gem devise Devise là một giải pháp xác thực cho Rails được tích hợp với Warden và được cung cấp bởi những người tuyệt vời tại Plataformatec. Devise cung cấp 10 mô-đun khác nhau, tùy vào sự cần thiết cho ứng dụng của bạn, bạn có thể chọn 1 vài mô-đun:

Module Mô tả chung Database Authenticatable Điều này mã hóa và lưu trữ một mật khẩu vào cơ sở dữ liệu để xác nhận tính xác thực của người dùng trong khi đăng nhập. Omniauthable Điều này giúp cho OmniAuth có thể hỗ trợ cho Devise. Người dùng ứng dụng của bạn sẽ có thể đăng nhập bằng tài khoản như Facebook, Twitter và Google Confirmable Điều này cho phép việc gởi các email với các chỉ dẫn sẽ giúp xác nhận một tài khoản. Recoverable Mô-đun này giúp những khi người dùng quên mật khẩu và cần phải khôi phục nó. Với điều này, thì người dùng sẽ có thể thiết lập lại mật khẩu. Registerable Điều này xử lý quá trình đăng ký của người dùng. Nó cũng cho phép người dùng chỉnh sửa và xoá các tài khoản của họ. Rememberable Mô-đun này làm cho ứng dụng của bạn có thể nhớ một người dùng đã đăng nhập bằng cách lưu trữ một cookie. Trackable Mô-đun này giúp theo dõi tài khoản đăng nhập, mốc thời gian, và địa chỉ IP. Timeoutable Mô-đun này chịu trách nhiệm cho một phiên hết thời hạn mà đã không được kích hoạt trong một khoảng thời gian. Validatable Với mô-đun này, email và mật khẩu sẽ được kiểm tra tính hợp lệ. Lockable Điều này cung cập một lớp phụ của bảo mật, khi được kích hoạt, một tài khoản có thể bị khoá sau một số lần cố gắng đăng nhập thất bại. Cách sử dụng Truy cập đến thư mục ứng dụng của bạn và thả các gem sau đây vào Gemfile của bạn.

#Gemfile gem "devise", "~> 4.1" Bây giờ cài đặt Devise và các gem Bootstrap mà bạn vừa mới thêm vào.

bundle install Tiếp theo, bạn cần phải chạy lệnh Rails để cài đặt các tập tin cấu hình cho Devise:

rails generate devise:install Màn hình cmd sẽ hiện ra kết quả sau:

create config/initializers/devise.rb create config/locales/devise.en.yml

Some setup you must do manually if you haven't yet:

  1. Ensure you have defined default url options in your environments files. Here is an example of default_url_options appropriate for a development environment in config/environments/development.rb:

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

    In production, :host should be set to the actual host of your application.

  2. Ensure you have defined root_url to something in your config/routes.rb. For example:

    root to: "home#index"

  3. Ensure you have flash messages in app/views/layouts/application.html.erb. For example:

    <%= notice %>

    <%= alert %>

  4. If you are deploying on Heroku with Rails 3.2 only, you may want to set:

    config.assets.initialize_on_precompile = false

    On config/application.rb forcing your application to not access the DB or load models when precompiling your assets.

  5. You can copy Devise views (for customization) to your app by running:

    rails g devise:views Điều hướng đến layout ứng dụng của bạn, app/views/layouts/application.html.erb, và thêm vào thẻ body đoạn mã dưới đây:

<%= notice %>

<%= alert %>

Bạn cần phải định nghĩa tùy chọn URL mặc định cho môi trường phát triển của bạn. Thêm code ở dưới vào config/environments/development.rb.

config.action_mailer.default_url_options = {host: "localhost", port: 3000} Tạo model Bây giờ bạn cần tạo ra một model User cho Devise. Bạn có thể làm điều này bằng cách sử dụng terminal của bạn.

rails generate devise User Việc này sẽ tạo ra một tập tin user.rb trong thư mục app/models của bạn, được cấu hình như sau:

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 Lệnh mà bạn chạy cũng sửa đổi tập tin config/routes.rb của bạn bằng cách thêm một route cho Devise.

Rails.application.routes.draw do root "static_pages#home" devise_for :users end Bạn kiểm tra các route được tạo ra, chạy lệnh rake routes

Session routes for Authenticatable (default)

 new_user_session GET    /users/sign_in                    {controller:"devise/sessions", action:"new"}
     user_session POST   /users/sign_in                    {controller:"devise/sessions", action:"create"}

destroy_user_session DELETE /users/sign_out {controller:"devise/sessions", action:"destroy"}

Password routes for Recoverable, if User model has :recoverable configured

new_user_password GET    /users/password/new(.:format)     {controller:"devise/passwords", action:"new"}

edit_user_password GET /users/password/edit(.:format) {controller:"devise/passwords", action:"edit"} user_password PUT /users/password(.:format) {controller:"devise/passwords", action:"update"} POST /users/password(.:format) {controller:"devise/passwords", action:"create"}

Confirmation routes for Confirmable, if User model has :confirmable configured

new_user_confirmation GET /users/confirmation/new(.:format) {controller:"devise/confirmations", action:"new"} user_confirmation GET /users/confirmation(.:format) {controller:"devise/confirmations", action:"show"} POST /users/confirmation(.:format) {controller:"devise/confirmations", action:"create"} Sử dụng lệnh trên cũng tạo ra một file migrate: db/migrate/20151228154229_devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration def change create_table(:users) do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: ""

  ## Recoverable
  t.string   :reset_password_token
  t.datetime :reset_password_sent_at

  ## Rememberable
  t.datetime :remember_created_at

  ## Trackable
  t.integer  :sign_in_count, default: 0, null: false
  t.datetime :current_sign_in_at
  t.datetime :last_sign_in_at
  t.string   :current_sign_in_ip
  t.string   :last_sign_in_ip

  ## Confirmable
  # t.string   :confirmation_token
  # t.datetime :confirmed_at
  # t.datetime :confirmation_sent_at
  # t.string   :unconfirmed_email # Only if using reconfirmable

  ## Lockable
  # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
  # t.string   :unlock_token # Only if unlock strategy is :email or :both
  # t.datetime :locked_at

  t.timestamps null: false
end

add_index :users, :email, unique: true
add_index :users, :reset_password_token, unique: true
# add_index :users, :confirmation_token, unique: true
# add_index :users, :unlock_token, unique: true

end end Tại thời điểm này, bạn cần phải cập nhật cấu trúc cơ sở dữ liệu

rake db:migrate Thêm các trường khác cho model User Theo mặc đinh đăng nhập vào devise sử dụng email và mật khẩu, nhưng nếu bạn muốn người dùng đăng nhập với username duy nhất của họ thì sao? Nếu đó là những gì bạn muốn, thì bạn hoàn toàn có thể. Chúng ta hãy xem cách làm thế nào. Chạy lệnh dưới đây để thêm một số trường vào model User mà bạn cần:

rails generate migration AddFieldsToUSers Điều này sẽ thêm một số cột mới, trong đó có username vào bảng users của bạn. Cập nhật cơ sở dữ liệu của bạn:

rake db:migrate Cấu hình view Trong file config/initializers/devise.rb bạn cần cấu hình lại

config.scoped_views = true Bạn có thể generate ra toàn bộ view cho devise bằng cách gõ lệnh.

rails generate devise:views hoặc bỏ bớt đi các view không cần thiết bằng các thêm -v vào sau.

rails generate devise:views -v registrations confirmations Câu lệnh trên cũng tạo ra một file config/locates/devise.yml cài đặt I18n để hiển thị ra màn hình khi thực hiện các thao tác, bạn có thể thay đổi nó theo ý các bạn. Để thêm các trường mà bạn đã tạo ở bước trước, chúng ta phải chỉnh sửa trang đăng nhập, đăng ký và cập nhật thông tin người dùng. Ở đây mình đang muốn đăng nhập bằng username nên ta chỉnh sửa như sau: Đăng ký app/views/devise/registrations/new.html.erb

Sign up

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> <%= devise_error_messages! %>

<%= f.label :email %>
<%= f.email_field :email, autofocus: true, class: "form-control" %>
<%= f.label :username %> <%= f.text_field :username, class: "form-control" %>
<%= f.label :password %> <% if @minimum_password_length %> (<%= @minimum_password_length %> characters minimum) <% end %>
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
<%= f.submit "Sign up", class: "btn btn-primary" %>
<% end %>

<%= render "devise/shared/links" %> Chỉnh sửa app/views/devise/registrations/edit.html.erb

Edit <%= resource_name.to_s.humanize %>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> <%= devise_error_messages! %>

<%= f.label :email %>
<%= f.email_field :email, autofocus: true, class: "form-control" %>

<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %>

Currently waiting confirmation for: <%= resource.unconfirmed_email %>
<% end %>

<%= f.label :username %> <%= f.text_field :username, class: "form-control" %>
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i>
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>
<%= f.label :password_confirmation %>
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %>
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i>
<%= f.password_field :current_password, autocomplete: "off", class: "form-control" %>
<%= f.submit "Update", class: "btn btn-primary" %>
<% end %>

Cancel my account

Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %>

<%= link_to "Back", :back %> Đăng nhập app/views/devise/sessions/new.html.erb

Log in

<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>

<%= f.label :username %>
<%= f.text_field :username, autofocus: true, class: "form-control" %>
<%= f.label :password %>
<%= f.password_field :password, autocomplete: "off", class: "form-control" %>

<% if devise_mapping.rememberable? -%>

<%= f.check_box :remember_me %> <%= f.label :remember_me %>
<% end -%>

<%= f.submit "Log in", class: "btn btn-primary" %>
<% end %>

<%= render "devise/shared/links" %> Điều hướng đến tập tin app/controllers/application_controller.rb. Bạn cần phải sửa đổi nó để cho phép việc sử dụng username hoặc các trường bạn cần. Sửa đổi nó thành như sau:

class ApplicationController < ActionController::Base

Prevent CSRF attacks by raising an exception.

For APIs, you may want to use :null_session instead.

protect_from_forgery with: :exception

before_action :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters added_attrs = [:username, :email, :password, :password_confirmation, :remember_me] devise_parameter_sanitizer.permit :sign_up, keys: added_attrs devise_parameter_sanitizer.permit :account_update, keys: added_attrs end end Cấu hình controller và route Mặc định, các route sign_in và sign_out khi sử dụng Devise trông giống như thế này: sign_in: http://localhost:3000/users/sign_in sign_out: http://localhost:3000/users/sign_out Để thay đổi nó, hãy vào config/routes.rb và thêm những thứ sau đây:

as :user do get "signin" => "devise/sessions#new" post "signin" => "devise/sessions#create" delete "signout" => "devise/sessions#destroy" end Một số phương thức helper hữu ích authenticate_user!: authenticate_user! là method ở trong controller. đảm bảo người dùng đã đăng nhập. Hàm này được gọi thông qua before_filter. Ví dụ:

class UserController < ApplicationController before_filter :authenticate_user! end Nếu như user chưa đăng nhập, như mặc dịnh nó sẽ bị redirect về trang login page. Nếu như user đăng nhập thành công, nó sẽ về trang root mà bạn đã cài đặt trong routes. user_signed_in? Dùng để kiểm tra người dùng đã đăng nhập hay chưa, bạn có thể dùng ở controller và views. Nếu người dùng chưa đăng nhập sẽ chuyển hướng về trang đăng nhập báo yêu cầu người dùng đăng nhập để tiếp tục. current_user Trả về người dùng đang đăng nhập user_session Trả về dữ liệu người dùng login

Giới thiệu chi tiết về từng Modules

  1. database_authenticatable: Đảm bảo mật khẩu được nhập chính xác và mã hóa chúng trước khi lưu vào CSDL
  2. confirmable: Đảm bảo người dùng đăng kí tài khoản sẽ xác nhận tài khoản qua mail mà devise gửi. Đây là 1 biện pháp để tránh tạo các tài khoản fake. Các option allow_unconfirmed_access_for: Thời gian bạn muốn cho phép người dùng truy cập vào tài khoản của họ trước khi xác nhận. Sau thời gian này, quyền truy cập của người dùng bị từ chối confirm_within: Thời gian có thể confirm. Bạn có thể sử dụng điều này để buộc người sử dụng phải xác nhận trong một khoảng thời gian nhất định. Xác nhận sẽ không tạo mã thông báo mới nếu yêu cầu xác nhận lặp lại. Sử dụng điều này để cho phép người dùng của bạn truy cập một số tính năng của ứng dụng mà không cần xác nhận tài khoản. reconfirmable: Yêu cầu bất kỳ thay đổi email nào đều được xác nhận (chính xác theo cách như xác nhận tài khoản ban đầu) sẽ được áp dụng.
  3. recoverable: Xử lí quên mật khẩu reset_password_keys: Các phím bạn muốn sử dụng khi khôi phục lại mật khẩu cho một tài khoản reset_password_within: Khoảng thời gian trong đó mật khẩu phải được đặt lại hoặc token hết hạn. sign_in_after_reset_password: Có hoặc không đăng nhập người dùng tự động sau khi đặt lại mật khẩu.
  4. registerable : Cho phép người dùng đăng kí và sau đó thay đổi thông tin tài khoản
  5. rememberable: Khi chọn Remember me trên form login. Dùng cookie lưu mật khẩu kể từ lần đăng nhập sau
  6. trackable: Lưu trữ thông tin đăng nhập (địa chỉ IP máy người dùng, thời gian đăng nhập, tổng số lần đăng nhập) Các thông tin được lưu vào các cột: sign_in_count: Tăng sau mỗi lần đăng nhập current_sign_in_at: Đánh dấu thời gian khi người dùng đăng nhập last_sign_in_at: Thời gian đăng nhập trước đó current_sign_in_ip: IP truy cập khi người dùng đăng nhập last_sign_in_ip: IP truy cập lần trước đăng nhập
  7. validatable : Đảm bảo email, mật khẩu phù hợp với một định dạng cụ thể. Có các option tương ứng là email_regexp: Biểu thức chính quy để xác nhận tính hợp lệ của email password_length: Xác định độ dài của mật khẩu.
  8. lockable: Giới hạn số lần đăng nhập sai. Hạn chế truy cập tài khoản trong 1 khoảng thời gian và gửi email bao gồm link để mở khóa tài khoản. Có các options để tùy biến như: maximum_attempts: Số lần nhập sai chấp nhận trước khi khóa người dùng. lock_strategy: khóa người dùng bằng :failed_attempts hoăc :none unlock_strategy: Bỏ khóa tài khoản bằng cách dùng :time, :email, :both hoặc :none. unlock_in: thời gian khóa tài khoản sau khi bị khóa. Chỉ khả dụng khi unlock_strategy là :time hoặc :both. unlock_keys: key sử dụng khi khóa và mở khóa tài khoản. Để tìm hiểu rõ hơn về các option này các bạn có thể tham khảo ở đây

Tổng kết Trên đây là những điều mà mình đã tìm hiểu được về gem devise, với bài viết này mong rằng các bạn mới nghiên cưu về Rails sẽ biết các sử dụng gem hữu ích này. Mình rất mong nhận đước sự góp ý và bổ sung từ các bạn. Cảm ơn mọi người đã dành thời gian đọc bài viết. Chúc mọi người học tập hiệu quả.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí