Devise Auth cho ứng dụng Rails sử dụng JSON Webservice
Chúng ta vẫn dùng thường dùng Rails để tạo ra các ứng dụng web và khi muốn tạo một ứng dụng mobile-friendly thì có hai con đường có thể chọn: hoặc là thiết kế một giao diện responsive hoặc là sẽ phát triển một ứng dụng cho các thiết bị di dộng. Để tạo ra một ứng dụng di động chúng ta phải tạo ra ...
Chúng ta vẫn dùng thường dùng Rails để tạo ra các ứng dụng web và khi muốn tạo một ứng dụng mobile-friendly thì có hai con đường có thể chọn: hoặc là thiết kế một giao diện responsive hoặc là sẽ phát triển một ứng dụng cho các thiết bị di dộng. Để tạo ra một ứng dụng di động chúng ta phải tạo ra một giao diện để có thể kết nối tới server của ứng dụng Rails, đó là khi Web services phát huy tác dụng. Trong bài viết này, chúng ta sẽ thử xây dựng một JSON Web service cho ứng dụng Rails
Mục đích của chúng ta là xây dựng một API cho module xác thực người dùng sử dụng một gem rất quen thuộc là Devise. Tuy nhiên vì lý do bảo mật mà trong build mới nhất Devise đã bỏ đi tính năng token authentication.
Nhưng token authentication là gì? Có chức năng gì mà lại bị Devise bỏ đi?
Hiểu một cách đơn giản, authentication_token giống như một thẻ nhân viên, khi bạn đi vào công ty (sign in) thì bạn cần phải có, đi đến mỗi phòng ban khác nhau bảo vệ sẽ nhìn thẻ và biết được bạn có quyền đi vào không.
Khi người dùng send một request lên server thì sẽ đính kèm với authentication_token. Có hai cách để sử dụng token, thêm vào query string hoặc qua HTTP header.
Token authentication có vẻ rất quan trọng, vậy phải làm sao?
Nắng đã có mũ, mưa đã có ô, lạnh cảm cúm đã có tiffi, chưa có token auth đã có gem simple_token_authentication
Dạo đầu đủ rồi, bây giờ chúng ta sẽ bắt đầu thực hiện:
Tạo Rails app
rails new webservice_demo
Add gem và cài đặt
gem "devise" gem "simple_token_authentication"
bundle install
Cài đặt model sử dụng Devise Authenticate
rails generate devise:install rails generate devise User
Disable CRFS cho JSON request
application_controller.rb
protect_from_forgery with: :null_session
Tạo route cho API
Rails.application.routes.draw do devise_for :users namespace :api do namespace :v1 do devise_scope :user do post "sign_up", :to => 'registrations#create' post "sign_in", :to => 'sessions#create' delete "sign_out", :to => 'sessions#destroy' end end end end
Tạo controller cho API
Trong thư mục app/controllers/api/v1 tạo các file:
- applications_controller.rb (Controller của route "api/v1/")
class Api::V1::ApplicationController < ActionController::API acts_as_token_authentication_handler_for User, {fallback: :none} respond_to :json private def current_user @current_user ||= User.find_by authentication_token: request.headers["Authorization"] #token thông qua header end def authenticate_user_from_token render json: {message: "You are not authenticated"}, status: 401 if current_user.nil? end end def ensure_params_exist return unless params[:user].blank? render json: {message: "Missing params"}, status: 422 end def load_user_authentication @user = User.find_by_email user_params[:email] return login_invalid unless @user end def login_invalid render json: {message: "Invalid login"}, status: 200 end end
- registrations_controller.rb (Controller của route "api/v1/sign_up")
class Api::V1::RegistrationsController < Devise::RegistrationsController before_action :ensure_params_exist respond_to :json def create user = User.new user_params if user.save render json: {message: "Registration has been completed",user: user}, status: 200 else warden.custom_failure! render json: {message: error_messages(user.errors.messages), status: 200 end end private def user_params params.require(:user).permit :email, :password, :password_confirmation end end
- sessions_controller.rb (Controller của route "api/v1/sign_in")
class Api::V1::SessionsController < Devise::SessionsController before_action :ensure_params_exist, only: [:create, :destroy] before_action :load_user_authentication respond_to :json def create if @user.valid_password? user_params[:password] sign_in @user, store: false render json: {message: "Signed in successfully", user: @user, status: 200 return end invalid_login_attempt end def destroy if @user.authentication_token == user_params[:authentication_token] #token thông qua query string sign_out @user render json: {message: "Signed out"}, status: 200 else render json: {message: "Invalid token"}, status: 200 end end private def user_params params.require(:user).permit :email, :password, :authentication_token end def invalid_login_attempt render json: {message: "Sign in failed"}, status: 200 end end
Sau khi viết xong phần code cho server, bạn hãy sử dụng POSTMAN để tạo các request tới server.
- Đăng ký: gửi request POST tới url /api/v1/sign_up với params
{ "email": "test@gmail.com", "password": "12345678", "password_confirmation": "12345678" }
- Đăng nhập: gửi request POST tới url /api/v1/sign_in với params
{ "email": "test@gmail.com", "password": "12345678" }
- Đăng xuất: gửi request DELETE tới url /api/v1/sign_out với params
{ "authentication_token": "token của user" }
Vậy là chúng ta đã tạo xong một API để thực hiện việc đăng ký, đăng nhập cho ứng dụng Rails server thông qua Devise. Bài viết đầu tiên chắc chắn sẽ còn nhiều thiếu xót, mong mọi người góp ý, bổ sung.
Thân ái và quyết thắng