Giới thiệu gem Doorkeeper

Doorkeeper là 1 gem giúp bạn thực hiện OAuth 2 provider trong ứng dụng của bạn 1 các dễ dàng.

Cài đặt

Thêm vào Gemfile và chạy lệnh bundle

gem "doorkeeper"

Chạy lệnh generate để tạo ra các file config và local

rails generate doorkeeper:install 

Cấu hình

Active Record

Mặc định doorkeeper được thiết lập để sử dụng cho active record, để bắt đầu, hãy chạy lệnh migration

rails generate doorkeeper:migration

Nếu bạn muốn gán foreign keys cho migration của bạn, thêm dòng sau vào file migrate vừa mới được tạo ra

add_foreign_key :table_name, :users, column: :resource_owner_id

(ví dụ nếu như bạn muốn dùng User để làm resource owner)

ORMs khác

Tham khảo Other ORMs

Routes

Khi chạy lệnh rails generate doorkeeper:install, use_doorkeeper sẽ được tự động thêm vào routes

Rails.application.routes.draw do
  use_doorkeeper
  # your routes
end

Khi đó bạn sẽ có các routes sau:

GET       /oauth/authorize/:code
GET       /oauth/authorize
POST      /oauth/authorize
DELETE    /oauth/authorize
POST      /oauth/token
POST      /oauth/revoke
resources /oauth/applications
GET       /oauth/authorized_applications
DELETE    /oauth/authorized_applications/:id
GET       /oauth/token/info

đọc wiki để biết rõ hơn các sử dụng từ routes này

Authenticating

Bạn cần configure Doorkeeper để có thể dử dụng cho resource_owner và authentication. Chỉnh sửa trong file config/initializers/doorkeeper.rb:

Doorkeeper.configure do
  resource_owner_authenticator do
    User.find_by_id(session[:current_user_id]) || redirect_to(login_url)
  end
end

Internationalization (I18n)

CÁc file ngôn ngữ có thể xem trong I18n repository

Protecting resources with OAuth (a.k.a trong API)

Để có thể bảo vệ API của bạn với OAuth , chỉ cần đặt before_action cho tất cả các action mà bạn muốn bảo vệ: Ví dụ:

class Api::V1::ProductsController < Api::V1::ApiController
  before_action :doorkeeper_authorize! # Sẽ yêu cầu access token cho tất cả các action

  # các action của bạn
end

Khi đã có before_action :doorkeeper_authorize!, mỗi request của bạn trong Header cần phải có Authorization: access token

Access Token Scopes

Bạn cũng có thể yêu cầu access token phải có scope cụ thể trong các actions nhất định Configure scope trong initializers/doorkeeper.rb:

Doorkeeper.configure do
  default_scopes :public # nếu không có scope được yêu cầu, sẽ được sử dụng theo mặc định
  optional_scopes :admin, :write
end

Và trong controller:

class Api::V1::ProductsController < Api::V1::ApiController
  before_action -> { doorkeeper_authorize! :public }, only: :index
  before_action only: [:create, :update, :destroy] do
    doorkeeper_authorize! :admin, :write
  end
end

Ở đây có 1 chú ý phân biệt giữa

doorkeeper_authorize! :admin, :write 

doorkeeper_authorize! :admin
doorkeeper_authorize! :write

Trường 1 là access token sẽ được yêu cầu sopce :admin hoặc scope :write, trường hợp 2 là yêu cầu cả 2 scope

Authenticated resource owner

Nếu bạn muốn trả lại dữ liệu dựa trên current resource owner, nói cách khác là access token owner, bạn có thể muốn định nghĩa một method trong controller của bạn trả về resource owner instance

class Api::V1::CredentialsController < Api::V1::ApiController
  before_action :doorkeeper_authorize!
  respond_to    :json

  # GET /me.json
  def me
    respond_with current_resource_owner
  end

  private

  # Tìm ra user là chủ của access token
  def current_resource_owner
    User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
  end
end

Vậy là bạn đã có thể tìm ra được current_resource_owner(chính xác là 1 user) thông qua access token được gửi kèm lên từ Header

Các bạn có thể tìm hiểu kĩ hơn tại gem Doorkeeper