+2

Twilio và hệ thống xác thực qua OTP

Giới thiệu

Twilio là một nền tảng truyền thông đám mây. Twilio cho phép các nhà phát triển phần mềm thực hiện và nhận cuộc gọi điện thoại, gửi và nhận tin nhắn văn bản theo chương trình và thực hiện các chức năng giao tiếp khác bằng cách sử dụng các API dịch vụ web của mình.

Trong bài chia sẻ ngày hôm nay, mình sẽ sử dụng chức năng gửi sms của Twilio để thực hiện xác thực người dùng. Sau đây là cách mình đã thực hiện nó trong Ruby on Rails

Đăng kí tài khoản

Trước tiên vào đây để đăng kí tài khoản

Lưu ý: Dùng số điện thoại của nhà mạng Viettel(các nhà mạng khác khi sử dụng, trong quá trình Free Trial sẽ bị lỗi)

  • Get a trial phone number
  • ACCOUNT SID
  • AUTH TOKEN
  • Sender phone number: +15023092048

Chuẩn bị và thực hiện thử nghiệm

  • Tạo repo mới, hoặc thực hiện lệnh sau(mình dùng lại repo của bài viết trước)
git clone [email protected]:loctx-2273/upload-file-with-carrierwave.git
  • Chạy seed
rails db:seed
  • Thêm 3 gem mới
gem "config" # settings.yml
gem "figaro" # env application.yml (mình có để file application.sample.yml)
gem "twilio-ruby" # twilio service
bundle install
bundle exec figaro install
rails g config:install
  • rails c
client = Twilio::REST::Client.new Settings.twilio.account_sid, Settings.twilio.auth_token
client.messages.create from: Settings.twilio.sender_phone_number, to: "+84865787769", body: "This is otp code"

Settings.twilio.account_sid, Settings.twilio.auth_token, và Settings.twilio.sender_phone_number: Tương ứng với các thông tin get được phía trên.

Lưu ý: to: "+84865787769", các bạn sử dụng chính số điện thoại vừa verify Twilio system phía trên

Thấy có vẻ khả quan rồi, chúng ta qua phần coding 👇

Coding và kết quả

Ở phần này, mình sẽ thực hiện chức năng cập nhật số điện thoại cho user trong hệ thống:

  • B1: Gửi yêu cầu đổi số điện thoại(cần xác thực người dùng)
  • B2: Verify one time pasword và cập nhật số điện thoại mới

Với yêu cầu trên, mình dự định sẽ tạo ra 3 service: Xử lý yêu cầu cập nhật số điện thoại, Gửi OTP tới người dùng, Xác thực và cập nhật số điện thoại mới.

  • Add field mới:
rails g migration add_field_to_use
class AddFieldToUser < ActiveRecord::Migration[6.1]
  def change
    add_column :users, :otp_code, :integer
    add_column :users, :otp_code_sent_at, :datetime
    add_column :users, :phone_number, :string
  end
end
  • routes.rb
post "users/send_sms_verification"
post "users/update_phone_number"
  • user_controller.rb
def send_sms_verification
  SendOtpVerificationService.call current_user
  render json: {status: :ok, message: "Send otp verification successful"}, status: :ok
end

def update_phone_number
  service = UpdatePhoneNumberService.new current_user, params
  service.call
  if service.error
    render json: {status: :unprocessable_entity, message: "Update phone number fails, otp code incorrect"}, status: :unprocessable_entity
  else
    result_data = {phone_number: current_user.phone_number}
    render json: {status: :ok, message: "Update phone number successful", data: result_data}, status: :ok
  end
end
  • SendOtpVerificationService: Xử lý yêu cầu cập nhật số điện thoại
class SendOtpVerificationService < ApplicationService
  attr_reader :user

  def initialize user
    @user = user
  end

  def call
    user.update otp_code: otp_code, otp_code_sent_at: Time.zone.now
    SendSmsService.call user.phone_number, otp_code
  end

  private

  def otp_code
    @otp_code ||= SecureRandom.random_number(10**6).to_s
  end
end

Ở service này, thực hiện update otp_code random(6 số) vào db và send otp code tới phone_number của current_user

  • SendSmsService: Gửi OTP tới người dùng
class SendSmsService < ApplicationService
  attr_reader :client, :phone_number, :message

  def initialize phone_number, message
    @client = Twilio::REST::Client.new Settings.twilio.account_sid, Settings.twilio.auth_token
    @phone_number = phone_number
    @message = message
  end

  def call
    client.messages.create from: Settings.twilio.sender_phone_number, to: receive_phone_number, body: message
  rescue Twilio::REST::RestError
    false
  end

  private

  def receive_phone_number
    "+84" + phone_number.delete_prefix("0")
  end
end

Ở service này, khởi tạo một Twilio service. Gửi message tới phone_number input(message cụ thể ở đây là otp code)

Thử nghiệm kết quả bằng Postman:

1 otp code đã được gửi tới số điện thoại tương của current_user:

2.7.2 :005 > User.first.otp_code
  User Load (0.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => 612927 
2.7.2 :006 >

Có vẻ uy tín 💯

  • UpdatePhoneNumberService: Xác thực và cập nhật số điện thoại mới
class UpdatePhoneNumberService < ApplicationService
  attr_reader :user, :params, :error

  def initialize user, params
    @user = user
    @params = params
    @error = false
  end

  def call
    return @error = true if params[:otp_code].to_i != user.otp_code

    user.update phone_number: params[:phone_number], otp_code: nil, otp_code_sent_at: nil
  end
end

Thực hiện check otp được gửi <-> otp người dùng nhập, cập nhật số điện thoại mới, và reset otp_code

Chạy thử:

2.7.2 :007 > User.first.phone_number
  User Load (0.3ms)  SELECT "users".* FROM "users" ORDER BY "users"."id" ASC LIMIT ?  [["LIMIT", 1]]
 => "0978171197" 
2.7.2 :008 >

Kết

Source Demo

Trên đây là cách sử dụng Twilio để thực hiện xác thực bằng OTP cho hệ thống mà mình đã thực hiện. Tất nhiên sẽ không tránh khỏi những thiếu sót về hình thức cũng như nội dung, mong bạn đọc góp ý để mình hoàn thiện hơn cho bạn đọc sau.

Cám ơn đã dành thời gian đọc bài chia sẻ của mình 😍😍😍


All Rights Reserved

Viblo
Let's register a Viblo Account to get more interesting posts.