Khám phá Devise, Phần 1
() translation by (you can also view the original English article)
Trong một số bài viết trước đây của tôi về upload hình ảnh trong Rails, tôi đã đề cập đến Devise nhưng không đi sâu vào nó. Trong hướng dẫn này, tôi sẽ dạy bạn về Devise.
Sẵn sàng chứ? Hãy bắt đầu thôi!
Giới thiệu Devise và các Mô-đun
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 các mô-đun khác nhau:
- Xác thực Cơ sở dữ liệu: Đ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.
- Xác thực với Omniauth: Đ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.
- Xác nhận: Đ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.
- Khôi phục: 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.
- Đăng ký: Đ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ọ.
- Khả năng nhớ: 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.
- Theo dõi: 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.
- Quá thời gian: 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.
- Kiểm tra hợp lệ: Với mô-đun này, email và mật khẩu sẽ được kiểm tra tính hợp lệ.
- Khả năng khoá: Đ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.
Tích hợp Devise
Với mục đích của hướng dẫn này, chúng ta sẽ tạo ra một ứng dụng Rails, mà chúng ta sẽ sử dụng để kiểm tra hoạt động của Devise. Hãy tiến hành thôi!
rails new devise-app -T
Cờ -T
nói với Rails để tạo ra các ứng dụng mà không có bộ kiểm thử mặc định. 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.
1 |
#Gemfile |
2 |
|
3 |
gem 'devise', '~> 4.1' |
4 |
gem 'bootstrap-sass', '~> 3.3' |
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
Đổi tên tập tin app/assets/stylesheets/application.css
thành app/assets/stylesheets/application.scss
và thêm các dòng sau đây vào đó:
1 |
#app/assets/stylesheets/application.scss |
2 |
|
3 |
@import "bootstrap-sprockets"; |
4 |
@import "bootstrap"; |
Mở tập tin app/assets/javascripts/application.js
và yêu cầu bootstrap-sprockets
. Nó sẽ trông như thế này:
1 |
#app/assets/javascripts/application.js |
2 |
|
3 |
//= require jquery |
4 |
//= require bootstrap-sprockets |
5 |
//= require jquery_ujs |
6 |
//= require turbolinks |
7 |
//= require_tree . |
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. Bạn làm điều đó bằng cách chạy lệnh này:
rails generate devise:install
Lệnh tạo ra các thứ sau đây trên terminal của bạn. Bạn nên đọc nó để hiểu những gì đã xảy ra.
1 |
create config/initializers/devise.rb |
2 |
create config/locales/devise.en.yml |
3 |
=============================================================================== |
4 |
|
5 |
Some setup you must do manually if you haven't yet: |
6 |
|
7 |
1. Ensure you have defined default url options in your environments files. Here |
8 |
is an example of default_url_options appropriate for a development environment |
9 |
in config/environments/development.rb: |
10 |
|
11 |
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } |
12 |
|
13 |
In production, :host should be set to the actual host of your application. |
14 |
|
15 |
2. Ensure you have defined root_url to *something* in your config/routes.rb. |
16 |
For example: |
17 |
|
18 |
root to: "home#index" |
19 |
|
20 |
3. Ensure you have flash messages in app/views/layouts/application.html.erb. |
21 |
For example: |
22 |
|
23 |
<p class="notice"><%= notice %></p> |
24 |
<p class="alert"><%= alert %></p> |
25 |
|
26 |
4. If you are deploying on Heroku with Rails 3.2 only, you may want to set: |
27 |
|
28 |
config.assets.initialize_on_precompile = false |
29 |
|
30 |
On config/application.rb forcing your application to not access the DB |
31 |
or load models when precompiling your assets. |
32 |
|
33 |
5. You can copy Devise views (for customization) to your app by running: |
34 |
|
35 |
rails g devise:views |
36 |
|
37 |
=============================================================================== |
Lệnh này cũng tạo ra hai tập tin, mà bạn có thể tìm thấy trong thư mục config
. Nó cũng cung cấp cho chúng ta một số chỉ dẫn về những gì chúng ta nên làm.
Điều hướng đến layout ứng dụng của bạn, app/views/layouts/application.html.erb
, và làm cho nó trông giống như những gì tôi có ở dưới đây:
1 |
#app/views/layouts/application.html.erb |
2 |
|
3 |
<!DOCTYPE html>
|
4 |
<html>
|
5 |
<head>
|
6 |
<title>DeviseApp</title> |
7 |
<%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track' => true %> |
8 |
<%= javascript_include_tag 'application', 'data-turbolinks-track' => true %> |
9 |
<%= csrf_meta_tags %> |
10 |
</head>
|
11 |
<body>
|
12 |
<div class="container-fluid"> |
13 |
<p class="notice"><%= notice %></p> |
14 |
<p class="alert"><%= alert %></p> |
15 |
</div>
|
16 |
|
17 |
<div class="container-fluid"> |
18 |
<%= yield %> |
19 |
</div>
|
20 |
|
21 |
</body>
|
22 |
</html>
|
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
.
1 |
#config/environments/development.rb |
2 |
|
3 |
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } |
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. Tập tin được tạo ra sẽ trông giống như thế này:
1 |
class User < ActiveRecord::Base |
2 |
# Include default devise modules. Others available are: |
3 |
# :confirmable, :lockable, :timeoutable and :omniauthable |
4 |
devise :database_authenticatable, :registerable, |
5 |
:recoverable, :rememberable, :trackable, :validatable |
6 |
end
|
Bạn có thể thấy rằng nó có chứa các mô-đun mặc định mà tôi đã đề cập ở trên. 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. Bạn nên kiểm tra đó.
Tại thời điểm này, bạn cần phải di chuyển cơ sở dữ liệu của bạn. Bạn làm điều đó bằng cách chạy:
rake db:migrate
Xác thực bằng cách sử dụng Devise
Bây giờ bạn cần tạo ra một PagesController
và bao quanh nó bằng Devise authentication - điều này sẽ ngăn chặn những người không được phép nhìn thấy trang.
rails generate controller Pages index
Mở tập tin routes của bạn và thiết lập thư mục gốc của ứng dụng của bạn.
1 |
#config/routes.rb |
2 |
|
3 |
Rails.application.routes.draw do |
4 |
devise_for :users |
5 |
root to: "pages#index" |
6 |
end |
Mở PagesController
của bạn ra và thêm sự xác thực cho trang index
và new
của bạn.
1 |
#app/controllers/pages_controller.rb |
2 |
|
3 |
class PagesController < ApplicationController |
4 |
before_action :authenticate_user!, only: [:index, :new] |
5 |
|
6 |
def index |
7 |
end
|
8 |
|
9 |
def new |
10 |
end
|
11 |
end
|
Đoạn mã chỉ ra rằng các trang index
và new
chỉ có thể truy xuất bởi những người dùng đã đăng ký. Mở terminal của bạn và bắt đầu chạy rails server
của bạn. Truy cập vào http://localhost:3000
trên trình duyệt và bạn sẽ tự động được chuyển hướng đến trang đăng nhập của Devise.
Đăng nhập mà không sử dụng Email
Theo mặc đinh các phương tiện đăng nhập vào Devise liên quan đến việc sử dụng email và mật khẩu. Nhưng nếu bạn muốn cho phép 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:
rails generate migration AddUsernameToUSers username:string
Điều này sẽ thêm một cột mới cho username
trong bảng users
của bạn. Di chuyển cơ sở dữ liệu của bạn.
rake db:migrate
Bạn cần phải thêm một trường vào các view của bạn mà người dùng của bạn có thể nhập username của họ. Khi bạn truy cập đến thư mục app/views
của bạn, bạn sẽ không tìm thấy bất kỳ tập nào kết xuất các view Devise của bạn. Điều này là bởi vì Devise tải các view từ bộ gem của nó. Để điều chỉnh nó, bạn có để tạo ra các bản sao của các view. Lệnh dưới đây thực hiện điều đó.
rails generate devise:views
Điều này sẽ tạo ra một số thư mục và tập tin trong thư mục app/views
của bạn.
Bạn sẽ cần phải chỉnh sửa trang đăng nhập, đăng ký và cập nhật thông tin người dùng. Chỉ cần dán các đoạn mã dưới đây vào tập tin tương ứng của chúng.
Đăng ký
1 |
#app/views/devise/registrations/new.html.erb |
2 |
|
3 |
<h2>Sign up</h2> |
4 |
|
5 |
<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %> |
6 |
<%= devise_error_messages! %> |
7 |
|
8 |
<div class="form-group"> |
9 |
<%= f.label :email %><br /> |
10 |
<%= f.email_field :email, autofocus: true, class: "form-control" %> |
11 |
</div>
|
12 |
|
13 |
<div class="form-group"> |
14 |
<%= f.label :username %> |
15 |
<%= f.text_field :username, class: "form-control" %> |
16 |
</div>
|
17 |
|
18 |
<div class="form-group"> |
19 |
<%= f.label :password %> |
20 |
<% if @minimum_password_length %> |
21 |
<em>(<%= @minimum_password_length %> characters minimum)</em> |
22 |
<% end %><br /> |
23 |
<%= f.password_field :password, autocomplete: "off", class: "form-control" %> |
24 |
</div>
|
25 |
|
26 |
<div class="form-group"> |
27 |
<%= f.label :password_confirmation %><br /> |
28 |
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %> |
29 |
</div>
|
30 |
|
31 |
<div class="actions"> |
32 |
<%= f.submit "Sign up", class: "btn btn-primary" %> |
33 |
</div>
|
34 |
<% end %> |
35 |
|
36 |
<%= render "devise/shared/links" %> |
Chỉnh sửa
1 |
#app/views/devise/registrations/edit.html.erb |
2 |
|
3 |
<h2>Edit <%= resource_name.to_s.humanize %></h2> |
4 |
|
5 |
<%= form_for(resource, as: resource_name, url: registration_path(resource_name), html: { method: :put }) do |f| %> |
6 |
<%= devise_error_messages! %> |
7 |
|
8 |
<div class="form-group"> |
9 |
<%= f.label :email %><br /> |
10 |
<%= f.email_field :email, autofocus: true, class: "form-control" %> |
11 |
</div>
|
12 |
|
13 |
<% if devise_mapping.confirmable? && resource.pending_reconfirmation? %> |
14 |
<div>Currently waiting confirmation for: <%= resource.unconfirmed_email %></div> |
15 |
<% end %> |
16 |
|
17 |
<div class="form-group"> |
18 |
<%= f.label :username %> |
19 |
<%= f.text_field :username, class: "form-control" %> |
20 |
</div>
|
21 |
|
22 |
<div class="form-group"> |
23 |
<%= f.label :password %> <i>(leave blank if you don't want to change it)</i><br /> |
24 |
<%= f.password_field :password, autocomplete: "off", class: "form-control" %> |
25 |
</div>
|
26 |
|
27 |
<div class="form-group"> |
28 |
<%= f.label :password_confirmation %><br /> |
29 |
<%= f.password_field :password_confirmation, autocomplete: "off", class: "form-control" %> |
30 |
</div>
|
31 |
|
32 |
<div class="form-group"> |
33 |
<%= f.label :current_password %> <i>(we need your current password to confirm your changes)</i><br /> |
34 |
<%= f.password_field :current_password, autocomplete: "off", class: "form-control" %> |
35 |
</div>
|
36 |
|
37 |
<div class="actions"> |
38 |
<%= f.submit "Update", class: "btn btn-primary" %> |
39 |
</div>
|
40 |
<% end %> |
41 |
|
42 |
<h3>Cancel my account</h3> |
43 |
|
44 |
<p>Unhappy? <%= button_to "Cancel my account", registration_path(resource_name), data: { confirm: "Are you sure?" }, method: :delete %></p> |
45 |
|
46 |
<%= link_to "Back", :back %> |
Đăng nhập
1 |
#app/views/devise/sessions/new.html.erb |
2 |
|
3 |
<h2>Log in</h2> |
4 |
|
5 |
<%= form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %> |
6 |
<div class="form-group"> |
7 |
<%= f.label :username %><br /> |
8 |
<%= f.text_field :username, autofocus: true, class: "form-control" %> |
9 |
</div>
|
10 |
|
11 |
<div class="form-group"> |
12 |
<%= f.label :password %><br /> |
13 |
<%= f.password_field :password, autocomplete: "off", class: "form-control" %> |
14 |
</div>
|
15 |
|
16 |
<% if devise_mapping.rememberable? -%> |
17 |
<div class="form-group"> |
18 |
<%= f.check_box :remember_me %> |
19 |
<%= f.label :remember_me %> |
20 |
</div>
|
21 |
<% end -%> |
22 |
|
23 |
<div class="actions"> |
24 |
<%= f.submit "Log in", class: "btn btn-primary" %> |
25 |
</div>
|
26 |
<% end %> |
27 |
|
28 |
<%= render "devise/shared/links" %> |
Sử dụng trình soạn thảo văn bản của bạn, đ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. Sửa đổi nó sao cho trông giống như thế này:
1 |
#app/controllers/application_controller.rb |
2 |
|
3 |
class ApplicationController < ActionController::Base |
4 |
# Prevent CSRF attacks by raising an exception. |
5 |
# For APIs, you may want to use :null_session instead. |
6 |
protect_from_forgery with: :exception |
7 |
|
8 |
before_action :configure_permitted_parameters, if: :devise_controller? |
9 |
|
10 |
protected
|
11 |
|
12 |
def configure_permitted_parameters |
13 |
added_attrs = [:username, :email, :password, :password_confirmation, :remember_me] |
14 |
devise_parameter_sanitizer.permit :sign_up, keys: added_attrs |
15 |
devise_parameter_sanitizer.permit :account_update, keys: added_attrs |
16 |
end
|
17 |
end
|
Bây giờ người dùng có thể đăng nhập bằng username của mình. Tại thời điểm này, có một cái gì đó không đúng về ứng dụng của bạn. Khi người dùng đăng nhập vào, không có cách để đăng xuất. Điều này tạo ra hệ quả là một trải nghiệm người dùng không tốt. Tôi sẽ chỉ cho bạn cách khắc phục điều đó.
Từ terminal của bạn, tạo một thư mục mới gọi là shared
trong thư mục app/views
.
1 |
mkdir app/views/shared
|
2 |
touch app/views/shared/_navigation.html.erb
|
Tập tin mà bạn tạo ở trên là một phần nơi mà các mã cho thanh điều hướng của bạn sẽ được viết. Thả các mã sau đây vào đó.
1 |
#app/views/shared/_navigation.html.erb |
2 |
|
3 |
<nav class="navbar navbar-inverse"> |
4 |
<div class="container"> |
5 |
<div class="navbar-header"> |
6 |
<%= link_to 'Tutsplus Devise', root_path, class: 'navbar-brand' %> |
7 |
</div>
|
8 |
<div id="navbar"> |
9 |
<ul class="nav navbar-nav"> |
10 |
<li><%= link_to 'Home', root_path %></li> |
11 |
</ul>
|
12 |
<ul class="nav navbar-nav pull-right"> |
13 |
<% if user_signed_in? %> |
14 |
<li class="dropdown"> |
15 |
<a class="dropdown-toggle" data-toggle="dropdown" href="#"> |
16 |
<%= current_user.name %> |
17 |
<span class="caret"></span> |
18 |
</a>
|
19 |
<ul class="dropdown-menu" role="menu"> |
20 |
<li><%= link_to 'Profile', edit_user_registration_path %></li> |
21 |
<li><%= link_to 'Log out', destroy_user_session_path, method: :delete %></li> |
22 |
</ul>
|
23 |
</li>
|
24 |
<% else %> |
25 |
<li><%= link_to 'Log In', new_user_session_path %></li> |
26 |
<li><%= link_to 'Sign Up', new_user_registration_path %></li> |
27 |
<% end %> |
28 |
</ul>
|
29 |
</div>
|
30 |
</div>
|
31 |
</nav>
|
Bây giờ bạn cần kết xuất thanh điều hướng trong layout ứng dụng của bạn. Mở tập tin app/views/layouts/application.html.erb
và thả vào đó đoạn mã để kết xuất thanh điều hướng của bạn.
1 |
#app/views/layouts/application.html.erb |
2 |
|
3 |
... |
4 |
<div class="container-fluid"> |
5 |
<%= render "shared/navigation" %> |
6 |
|
7 |
<p class="notice"><%= notice %></p> |
8 |
<p class="alert"><%= alert %></p> |
9 |
</div>
|
10 |
... |
Tổng kết
Trong phần này bạn đã học cách cài đặt Devise và thêm sự chứng thực vào trong các trang của bạn. Tôi cũng đã đề cập đến một bộ phận riêng. Tôi sẽ bao quát nó trong một bài hướng dẫn riêng.
Trong phần tiếp theo, chúng ta sẽ bao quát sâu hơn một số phần. Tôi hy vọng điều này xứng đáng với thời gian mà bạn đã bỏ ra!