Remote Authentication với Devise và OmniAuth

1, Giới thiệu

providers.png

Bạn đã từng thấy những button như thế này xuất hiện trên một website nào đó mà bạn đã từng ghé thăm. Công dụng của chúng là khởi tạo quá trình đăng nhập vào hệ thống bằng tài khoản mạng xã hội, hay tài khoản trong một hệ thống lớn nào đó mỗi khi được click, loại đăng nhập này được gọi là remote authentication.

Remote authentication là một lược đồ ánh xạ authentication mà sử dụng các third-party services để xác định việc xác thực của người dùng có hợp lệ. Bằng việc sử dựng lược đồ này, người dùng có thể đăng nhập vào hệ thống khi mà họ đã đăng nhập vào third-party system mà không cần phải cung cấp mật khẩu hay password, hay nói cách khác họ có thể đăng nhập vào hệ thống mà không cần phải thực hiện quá trình đăng ký tài khoản.

Các website lớn hiện nay như Twitter, Facebook, Google đều cung cấp dịch vụ remote authentication cho người dùng của họ. Việc sử dụng dịch vụ này sẽ rất có lợi cho website của chúng ta khi số lượng người dùng hệ thống ngày càng lớn.

Bạn có thể thắc mắc rằng, tại sao các công ty lớn lại cung cấp dịch vụ remote authentication, họ không sợ gặp phải vấn đề về security, những lợi ích gì họ thu được khi cung cấp dịch vụ này ? Đầu tiên, để sử dụng dịch vụ này, chúng ta cần đăng ký một ứng dụng trên website của họ. Bằng cách này họ có thể theo dõi được các ứng dụng mà dùng dịch vụ của họ, họ có thể khóa các ứng dụng của chúng ta nếu chúng ta lạm dụng hay xâm phạm các điều khoản sử dụng của dịch vụ. Thứ hai, việc cung cấp các dịch vụ đó cũng mang lại lợi ích cho họ: người dùng phải đăng ký tài khoản trên site của họ trước khi có thể dùng nó để đăng nhập site khác. Như vậy việc cung cấp dịch vụ remote authentication lợi ích lớn nhất của các bên cung cấp đó là để tăng lượng người dùng website của họ

2, Các bước cài đặt remote authentication cho Rails application

Trong bài viết này tôi sẽ sử dụng devise gem để cài đặt tính năng remote authentication cho ứng dụng. Devise được xây dựng theo hướng có thể hỗ trợ remote authentication. Tuy nhiên, thực tế thì devise không có những functions để thực hiện mục đích này, và do đó chúng ta phải xây dựng tính năng này dựa trên devise. Devise có một Omniauthable module cho phép devise connect tới Omniauth, omniauth chính là thư viện mà chúng ta sẽ dùng kết hợp với devise để tạo remote authentication cho ứng dụng. Omniauth hỗ trợ nhiều provider authentication ví dụ: Facebook, Twitter, Google, Github,...Trong bài viết này tôi sẽ giới thiệu với các bạn remote authentication với 2 provider là facebook và twitter.

2.1, Cài đặt

Trong bài viết này, tôi giả sử bạn đã cài đặt gem devise và set up một số thứ cần thiết cho devise. Model cho authentication là User.

  • Thêm gem omniauth-twitter, omniauth-facebook vào Gemfile
gem 'omniauth-twitter'
gem 'omniauth-facebook'

Trên terminal run:

bundle install
  • Bật module omniauthable cho devise

Trong User model thêm module omniauthable vào như sau:

devise :database_authenticatable, :registerable, :omniauthable,
  :recoverable, :rememberable, :trackable, :validatable

2.2. Đăng ký Facebook application

Truy cập vào : https://developers.facebook.com/, tại mục 'ứng dụng của tôi' chọn 'Thêm ứng dụng mới'. Nhâp các thông tin theo yêu cầu. Cuối cùng bạn sẽ có một facebook app như sau:

face-app.png

Bạn cần nhớ App Id và App Secret của ứng dụng. Đây là 2 thông tin quan trọng để Omniauth kết nối tới facebook app của bạn.

2.3. Đưa Omniauth vào ứng dụng

a, Thêm 2 columns mới là 'provider' và 'uid' tới users table

rails g migration AddOmniauthToUsers provider:string uid:string
rake db:migrate

b, Khai báo provider vào config/initializers/devise.rb

config.omniauth :facebook, 'YOUR_APP_ID', 'YOUR_APP_SECRET'

Thay thế YOUR_APP_ID và APP_SECRET với app id và secret của bạn. Bạn cũng cần xác định permissions và scopes để xác định phạm vi của thông tin người dùng bạn cần lấy về.

config.omniauth :facebook, 'YOUR_APP_ID', 'YOUR_APP_SECRET',
  scope: 'email, public_profile,user_birthday,user_education_history,user_hometown,user_location,user_work_history'

c, Sau khi cấu hình facebook provider cho devise, bạn cần thêm dòng sau tới User model

devise :omniauthable, :omniauth_providers => [:facebook] Nếu bạn đang chạy rails server thì bạn cần restart nó để các thay đổi chúng ta vừa làm có hiệu lực.

d, Các url helper của facebook omniauth

Sau khi thực hiện các thay đổi trên User model, và nếu devise_for :users đã được thêm tới routes.rb file, devise sẽ tạo 2 url methods sau:

user_facebook_omniauth_authorize_path
user_facebook_omniauth_callback_path

Chú ý rằng devise không tạo *_url methods. Method thứ 2 trong 2 methods trên bạn sẽ không bao giờ sử dụng trực tiếp. Bạn chỉ cần thêm method thứ nhất tới layout của ứng dụng để cung cấp facebook authentication

<%= link_to 'Sign in with Facebook', user_facebook_omniauth_authorize_path %>

Nếu click vào link trên, bạn sẽ được đưa đến trang Facebook như sau:

last-face.png

Sau khi điền email, password bạn sẽ được đưa trở lại method callback của ứng dụng.

e, Implement callback method

  • Để implement callback method, đầu tiên cần thêm route cho callback method. Trong file config/routes.rb sửa lại devise_for như sau:
devise_for :users, :controllers => { :omniauth_callbacks => "user/omniauth_callbacks" }
  • Thêm app/controllers/users/omniauth_callbacks_controller.rb:
class User::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  def facebook
    # You need to implement the method below in your model (e.g. app/models/user.rb)
    @user = User.find_by_uid(request.env["omniauth.auth"])

    if @user.persisted?
      sign_in_and_redirect @user, :event => :authentication #this will throw if @user is not activated
      set_flash_message(:notice, :success, :kind => "Facebook") if is_navigational_format?
    else
      session["devise.facebook_data"] = request.env["omniauth.auth"]
      redirect_to new_user_registration_url
    end
  end

  def failure
    redirect_to root_path
  end
end

Ở đây, chúng ta thấy tất cả các thông tin lấy được từ facebook được lưu trong hash: request.env['omniauth.auth'].
Nếu có một user trong database có uid giống với uid lấy được từ facebook thì sign in và redirect về trang chủ. Ngược lại người dùng được redirect tới trang đăng ký đồng thời các thông tin get được từ facebook được lưu vào trong session

3, Kết luận

Như vậy, trong bài viết này tôi đã giới thiệu tới các bạn cách tạo cho rails application tính năng remote authentication cụ thể là qua facebook, với các provider khác như twitter hay Google các bạn cũng làm tương tự như làm với Facebook.
Cảm ơn các bạn đã đọc bài viết của tôi, hẹn gặp lại ở các bài viết tiếp theo.

Tài liệu tham khảo:

https://github.com/plataformatec/devise https://github.com/mkdynamic/omniauth-facebook http://sourcey.com/rails-4-omniauth-using-devise-with-twitter-facebook-and-linkedin/ https://coderwall.com/p/bsfitw/ruby-on-rails-4-authentication-with-facebook-and-omniauth http://willschenk.com/setting-up-devise-with-twitter-and-facebook-and-other-omniauth-schemes-without-email-addresses/