Xác thực 2 lớp trong Rails với Devise và Nexmo
Bài đăng này đã không được cập nhật trong 3 năm
Vào năm 2015, hơn 150 triệu hồ sơ người dùng đã bị đánh cắp và rò rỉ dữ liệu đã cho thấy mọi người vẫn có xu hướng sử dụng chung mật khẩu cho các trang web khác nhau. Vì vậy, để gia tăng an toàn bảo mật cho tài khoản, các ứng dụng đã sử dụng cơ chế xác thực hai lớp Two-factor authentication hay còn được gọi 2FA
. Mặc dù vẫn có nguy cơ bị hack , nhưng cách xác thực này đã tăng rất nhiều tính an toàn cho tài khoản người dùng.
Nếu bật tính năng xác thực thì khi đăng nhập vào tài khoản sẽ bị hỏi thêm 1 bước nữa. Yêu cầu nhập mã OTP để xác thực là chủ tài khoản thì mới có thể vào tài khoản và sử dụng.
Demo
Chúng ta sẽ thêm xác thực hai lớp vào ứng dụng Rails bằng Nexmo Verify API. Tôi sẽ tạo một trang web nhỏ tên là "Kittens & Co" - mạng xã hội để trao đổi mèo.
Tải ứng dụng tại đây:
# ensure you have Ruby and Bundler installed
git clone https://github.com/nexmo-community/nexmo-rails-devise-2fa-demo.git
cd nexmo-rails-devise-2fa-demo
bundle install
rake db:migrate RAILS_ENV=development
rails server
Sau đó vào 127.0.0.1:3000 trên trình duyệt và đăng ký.
Mặc định, ứng dụng thực hiện đăng ký và đăng nhập bằng Devise, tôi sẽ tập trung vào phương thức xác thực thứ 2. Ngoài ra, để giao diện đẹp hơn tôi đã thêm gem bootstrap-sass
và devise-bootstrap-templates
.
Mã nguồn cho phần đăng nhập cơ bản ở trên nhánh basic-login. Phần xác thực thứ 2 ở nhánh two-factor. Để thuận tiện, bạn có thể theo dõi thay đổi trên Github.
Xác thực Nexmo cho 2FA
Nexmo Verify là phương thức xác thực qua điện thoại được thực hiện đơn giản. Hầu hết các plugin xác thực 2 lớp sẽ yêu cầu bạn quản lý các mã xác thực, thời gian hiệu lực và gửi SMS. Tuy nhiên, những gì bạn thực sự cần biết là gọi 2 API.
Thêm Nexmo Verify vào ứng dụng:
- Thêm số điện thoại vào thông tin tài khoản.
- Yêu cầu xác thực khi đăng nhập nếu có số điện thoại trong tài khoản.
- Mã xác thực được gửi đến số điện thoại của người dùng và được dùng để đăng nhập.
Thêm số điện thoại
Thêm cột phone_number
vào bảng User
:
rails generate migration add_phone_number_to_users
# db/migrate/...add_phone_number_to_users.rb
class AddPhoneNumberToUsers < ActiveRecord::Migration
def change
add_column :users, :phone_number, :string
end
end
rake db:migrate
Tạo bản sao của view
bằng devise generate
:
# this is not the default generator but the one needed for the devise-bootstrap-templates gem
rails generate devise:views:bootstrap_templates
# uncomment and run the command below if you did not use the devise-bootstrap-templates gem
# rails generate devise:views:templates
Lệnh trên sẽ sao chép nhiều view
vào app/views/devise/
. Nhưng chúng ta không dùng hết các view này mà chỉ giữ lại: registrations/edit.html.erb
.
Thay đổi duy nhất trong view
này là thêm trường phone_number
ngay sau trường email
.
<!-- app/views/devise/registrations/edit.html.erb -->
<div class="form-group">
<%= f.label :phone_number %> <i>(Leave blank to disable two factor authentication)</i><br />
<%= f.number_field :phone_number, class: "form-control", placeholder: "e.g. 447555555555 or 1234234234234" %>
</div>
Bước cuối cùng là làm cho Devise
nhận thức được tham số bổ sung này. Nếu không có những dòng này phone_number
sẽ không được chấp nhận như là một tham số và sẽ bị mất sau khi form được gửi.
# app/controllers/application_controller.rb
...
before_filter :configure_permitted_parameters, if: :devise_controller?
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update, keys: [:phone_number])
end
...
Để kiểm tra, đến http: //localhost: 3000/users/sign_up , tạo một tài khoản, nhấp vào email của bạn ở góc trên cùng bên phải của màn hình, nhập số điện thoại và mật khẩu bạn đã sử dụng khi đăng ký và nhấp vào Update
. Số điện thoại sẽ được lưu vào cơ sở dữ liệu.
Gửi yêu cầu xác thực 2FA
Bây giờ, người dùng có thể thêm số điện thoại vào tài khoản của mình, có thể yêu cầu họ xác thực số điện thoại khi đăng nhập. Để gửi thông báo xác thực qua Nexmo Verify, thêm gem nexmo
vào ứng dụng.
# Gemfile
gem 'nexmo'
gem 'dotenv-rails', groups: [:development, :test]
bundle install
Như bạn thấy, chúng ta cũng cần thêm gem dotenv-rails
. Đây là ứng dụng có thể tải chứng chỉ API từ một tập tin .env
. Gem Nexmo tự động lấy các biến môi trường đó và sử dụng chúng để khởi tạo client. Bạn có thể tìm thấy các thông tin xác thực của mình trên trang cài đặt tài khoản Nexmo của bạn.
# .env
NEXMO_API_KEY='your_key'
NEXMO_API_SECRET='your_secret'
Có nhiều cách khác nhau thêm bước xác thực thứ 2 vào ứng dụng. Để đơn giản, chúng ta thêm vào trong before_action
của ApplicationController
nếu người dùng kích hoạt xác thực 2 lớp, đảm bảo rằng chúng được xác thực trước khi được phép tiếp tục.
# app/controllers/application_controller.rb
before_action :verify_user!, unless: :devise_controller?
def verify_user!
start_verification if requires_verification?
end
Đơn giản là kiểm tra nếu người dùng có số điện thoại trong hồ sơ và nếu giá trị session :verified
chưa được đặt.
# app/controllers/application_controller.rb
def requires_verification?
session[:verified].nil? && !current_user.phone_number.blank?
end
Để bắt đầu xác thực, gọi send_verification_request
(API #1) trên đối tượng Nexmo::Client
. Không cần phải qua thông tin xác thực API nào bởi vì nó đã được tạo thông qua các biến môi trường - nếu muốn kiểm tra có thể xem tại đây.
# app/controllers/application_controller.rb
def start_verification
result = Nexmo::Client.new.send_verification_request(
number: current_user.phone_number,
brand: "Kittens and Co",
sender_id: 'Kittens'
)
if result['status'] == '0'
redirect_to edit_verification_path(id: result['request_id'])
else
sign_out current_user
redirect_to :new_user_session, flash: {
error: 'Could not verify your number. Please contact support.'
}
end
end
Như vậy là đã vượt qua yêu cầu xác thực tên của ứng dụng. Điều này được sử dụng trong tin nhắn văn bản mà người dùng nhận được và thêm vào một số cá nhân hóa thương hiệu rất tốt.
Nếu tin nhắn được gửi thành công, tôi sẽ chuyển hướng người dùng đến trang để điền mã xác nhận.
Kiểm tra mã xác thực 2FA
Bước cuối cùng là để xác nhận lại mã xác thực người dùng nhận được. Ta cần thêm một trang mới.
Bắt đầu bằng thêm trong routes
.
# config/routes.rb
resources :verifications, only: [:edit, :update]
Và cũng tạo một controller
.
# app/controllers/verifications_controller.rb
class VerificationsController < ApplicationController
skip_before_action :verify_user!
def edit
end
def update
...
end
end
Để chắc chắn bỏ qua before_action
ta đã thêm vào ApplicationController
trước đó, ta dùng skip_before_action
để trình duyệt không bị redirect
vô hạn.
Tiếp theo, tạo view
để người dùng nhập mã xác thực.
<!-- app/views/verifications/edit.html.erb -->
<%= form_tag verification_path(id: params[:id]), method: :put do %>
<div class="form-group">
<%= label_tag :code %><br />
<%= number_field_tag :code, class: "form-control" %>
</div>
<%= submit_tag 'Verify', class: "btn btn-primary" %>
<% end %>
Người dùng nhập mã và verify. Trong action này chúng ta lấy request_id
và code
từ params
và dùng method check_verification_request
(API #2) xác thực.
# app/controllers/verifications_controller.rb
def update
confirmation = Nexmo::Client.new.check_verification_request(
request_id: params[:id],
code: params[:code]
)
if confirmation['status'] == '0'
session[:verified] = true
redirect_to :root, flash: { success: 'Welcome back.' }
else
redirect_to edit_verification_path(id: params[:id]), flash: { error: confirmation['error_text'] }
end
end
Khi xác nhận thành công, chúng tôi sẽ thiết lập trạng thái của người dùng là đã được xác thực và chuyển hướng về trang chính. Nếu không sẽ thông báo những gì đã xảy ra. Tra cứu mã trạng thái phản hồi tại đây.
Nếu bạn đang chạy ứng dụng, đăng xuất (nếu cần) và đăng nhập, bây giờ bạn sẽ nhận được yêu cầu xác thực.
Như vậy, chỉ cần gọi 2 API.
Bước tiếp
Nexmo API có nhiều tùy chọn hơn những gì tôi đã đề cập ở đây, từ tìm kiếm và kiểm soát các yêu cầu, thay đổi độ dài mã và thời gian hết hạn. Ứng dụng trên mặc dù đơn giản nhưng đã được kiểm chứng là thực sự mạnh mẽ. Hệ thống sẽ chuyển sang các cuộc gọi thoại nếu cần thiết, xử lý hết hạn các token
mà bạn không phải làm gì, ngăn ngừa sử dụng lại các mã xác thực.
Thư viện Nexmo của Ruby có thể làm được nhiều điều rất khác biệt so với tôi đã làm ở đây. Ví dụ: bạn có thể yêu cầu số điện thoại đăng ký từ người dùng, từ chối các tài khoản mới cho đến khi số điện thoại được xác nhận.
Nguồn: nexmo.com
All rights reserved