Gem Devise - Rails
Bài đăng này đã không được cập nhật trong 3 năm
Khi bạn làm việc với ngôn ngữ lập trình yêu thích của mình, bạn thường tìm kiếm các công cụ để làm cho công việc của mình dễ dàng hơn. Trong Ruby, những công cụ này (gems) được tạo ra hàng ngày, nhưng chỉ một số trong số chúng là đủ tốt để chiếm được cảm tình của các coder. Gem devise
là 1 trong những số đó. Nó được sử dụng rộng rãi hầu hết ở mọi project.
Gem Devise
là một giải pháp authentication linh hoạt cho Rails. Nó
- Dựa trên Rack
- Một solution MVC đầy đủ dựa trên Rails engines
- Cho phép nhiều models cùng đăng nhập tại một thời điểm
- Làm việc dựa trên module: Chỉ sử dụng những gì bạn thực sự cần. Nó chạy những module độc lập và riêng biệt
Cách hoạt động
Cài đặt trên Rails:
Giả sử ta muốn cài devise cho 1 model tên là User
echo "gem 'devise'" >> Gemfile # Hoặc sửa Gemfile thêm dòng: gem 'devise'
bundle install # Cài đặt gem
rails generate devise:install # Tạo file config và các file liên quan
rails generate devise user # Tạo model class, routes ..
rake db:migrate # Tạo table user
rails generate devise:views users # Tạo view
Devise Configuration
Sau khi cài đặt gem devise,bước tiếp theo ta config được xác định dựa trên 2 file chính
- global file,
config/initializers/devise.rb
. Nếu có gì đó thay đổi trong file này, chúng ta cần phải restart lại server. - Trong model user nơi đã cài đặt. Có thể tùy chỉnh chức năng thêm
Router
Ở router ta khai báo:
devise_for :users
Sẽ tự động sinh ra các router cần thiết như login, logout, reset password, edit password
# 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"}
Nếu có namspace ta đặt trong namespace:
namespace :publisher do
devise_for :account
end
Đoạn mã trên sẽ sử dụng publisher/sessions_controller thay vì devise/sessions_controller. Scoping: Bạn có thể đặt devise_for trong một scope:
scope "/my" do
devise_for :users
end
scope ":locale" do
devise_for :users
end
Bạn có thể yêu cầu config default_url_options trong ApplicationController. tự động thêm locale vào đường link
class ApplicationController < ActionController::Base
def self.default_url_options
{ locale: I18n.locale }
end
end
Custom router Thay đổi tên đường dẫn nếu bạn k muốn để tên mặc định
devise_scope :user do
get "/some/route" => "some_devise_controller"
end
devise_for :users
Devise Utility Methods
Các helper method hỗ trợ hay dùng và hữu ích nhất là:
- 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 EndUserBaseController < 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, Root routes là route mặc định được định nghĩa trong file config/route.rb
root to: 'tours#index'
Sử dụng authenticate_user! đảm bảo việc user đăng nhập nên ta hoàn toàn có thể sử dụng method current_user để truy cập database hay thao tác trên nó:
class SentMessagesController < EndUserBaseController
before_filter :authenticate_user!
def index
@sent_messages = current_user.sent_messages.all
end
end
Before_filter :authenticate_user!
đảm bảo current_user sẽ không bao giờ bị nil
- current_user: Trả về người dùng đang đăng nhập. Nó sẽ trả về nil khi người dùng chưa đăng nhập
- user_signed_in?: Trả về True hoặc False. True nếu user đã đăng nhập, và ngược lại
- sign_in(@user) , sign_out(@user) : Thực hiện login, logout user
- user_session: Trả về dữ liệu người dùng login.
Các tính năng - Modules
class User < ActiveRecord::Base
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, :lockable, :timeoutable
end
- 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
- confirmable: Đảm bảo việc 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ốiconfirm_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. Ví dụ:
User.find(1).confirm # returns true unless it's already confirmed
User.find(1).confirmed? # true/false
User.find(1).send_confirmation_instructions # manually send instructions
- 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ảnreset_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. - registerable : Cho phép người dùng đăng kí và sau đó thay đổi thông tin đăng nhập
- rememberable: Khi chọn Remember me trên form login. Dựa trên cookie giúp lưu mật khẩu kể từ lần đăng nhập sau
- 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ậpcurrent_sign_in_at
: Đánh dấu thời gian khi người dùng đăng nhậplast_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ậplast_sign_in_ip
: IP truy cập lần trước đăng nhập - 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. - 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 :noneunlock_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
Xử lý nhiều người dùng trong Devise
Trong phần này, chúng ta sẽ xem xét một số cách trong đó một số trường hợp sử dụng phổ biến liên quan đến hạn chế truy cập có thể được xử lý bằng các method của Devise
- Trường hợp 1: Đảm bảo tất cả các action trong các controller đều phải đăng nhập trước khi truy cập ngoại trừ trang login và đăng kí
class ApplicationController < ActionController::Base
# Ensures all actions invoke this (except those just below)
before_filer :authenticate_user!
end
class AuthenticationController < ApplicationController
# Turn off user authentication for all actions in this controller
skip_before_filer :authenticate_user!
def login
'...'
end
def register
'...'
end
end
- Trường hợp 2: Tất cả các action đều phải đăng nhập trước khi truy cập trừ 1 số action. Ví dụ :index, :show
class CrudController < ApplicationController
before_filer :authenticate_user!, except: [ :index, :show ]
end
class BlogsController < CrudController
end
class CommentsController < CrudController
end
- Trường hợp 3: Giả sử chúng ta muốn phân quyền truy cập cho người dùng,. Admin và user, cả 2 đều được đại diện bởi model riêng biệt. Một model User và Admin.
# All administrator controllers should inherit from this controller
class AdminController < ApplicationController
before_filer :authenticate_admin!
end
# All end-user controllers should inherit from this controller
class EndUserController < ApplicationController
before_filer :authenticate_user!
end
- Trường hợp 4: Giả sử chúng ta có người dùng và admin đều chia sẻ chung một model. Tuy nhiên trong trường hợp này admin được xác định bởi 1 flag lưu trong model có giá trị true, false.
class ApplicationController < ActionController::Base
before_filer :authenticate_user!
end
# All administrative controllers should inherit from this controller
class AdminController < ApplicationController
before_filter :ensure_admin!
private
def ensure_admin!
unless current_user.admin?
sign_out current_user
redirect_to root_path
return false
end
end
end
Testing
Bạn có thể tạo ra 1 devise user bằng cách
User.create!(email: "me@home.com", password: "Aa12345")
Một ví dụ rspec
describe BlogController do
let :user do
User.create!(email: "me@home.com", password: "watching the telly")
end
before { sign_in user }
context "creating a post" do
post :create, subject: 'matter', body: 'and soul'
expect(assigns(:blog)).to be_instance_of Blog
expect(:blog.try :subject).to eq 'matter'
expect(:blog.try :user).to eq user
end
end
Hi vọng bài viết có thể giúp ích cho bạn!
Nguồn tham khảo :
http://www.rubydoc.info/github/plataformatec/devise/master/Devise/Models
https://launchschool.com/blog/how-to-use-devise-in-rails-for-authentication
All rights reserved