Ngày nay, hầu hết các trang web đều cho phép người dùng đăng nhập bằng tài khoản mạng xã hội như Google, Twitter hay Facebook…Trong bài viết này, mình sẽ hướng dẫn mọi người cách thiết lập cho trang web của mình thực hiện tính năng này nhé.
Cài đặt gem và cấu hình
Đầu tiên, ta cài đặt các gem sau trong file Gemfile
gem "devise"
gem "omniauth"
gem "omniauth-google-oauth2"
gem "omniauth-rails_csrf_protection"
Thiết lập khai báo trong file: config/initializers/devise.rb
:
config.omniauth :google_oauth2, ENV["GOOGLE_OAUTH_CLIENT_ID"], ENV["GOOGLE_OAUTH_CLIENT_SECRET"], {scope: "email"}
Trong đó, GOOGLE_OAUTH_CLIENT_ID và GOOGLE_OAUTH_CLIENT_SECRET là 2 biến môi trường được thiết lập trong file config/application.yml. Mình sẽ hướng dẫn cách các bạn lấy hai giá trị này ngay sau đây:
Đầu tiên các bạn vào link sau:
https://console.developers.google.com
Chọn CREATE PROJECT
Sau khi tạo project thành công, bạn thiết lập các thông tin cần thiết tại Oauth consent screen
.
Sau khi điền các thông tin cần thiết, chọn Credentials > CREATE CREDENTISLS > Oauth client ID
Tại application type
, chọn Web application
Sau khi tạo xong, một cửa sổ popup hiển thị lên với
Your Client ID là giá trị của ENV[“GOOGLE_OAUTH_CLIENT_ID”]
Your Client Secret là giá trị của ENV[“GOOGLE_OAUTH_CLIENT_SECRET”]
Thêm trường uid và provider vào model (ở đây mình giả sử model là User)
rails generate migration AddOmniauthToUsers provider:string uid:string name:string
Run rails db:migrate
để thêm các trường này vào cơ sở dữ liệu
Cấu hình file routes.rb
Thêm dòng sau vào file:
devise_for :users, controllers: {omniauth_callbacks: "omniauth_callbacks"}
Nếu tại file routes, bạn có scope cho locale, thì dòng code này phải đề bên ngoài scope nhé.
Cấu hình controller
Tạo file mới tại app/controllers/omniauth_callbacks_controller.rb:
class OmniauthCallbacksController < Devise::OmniauthCallbacksController
def google_oauth2
@user = User.from_omniauth request.env["omniauth.auth"]
if @user.persisted?
flash[:notice] = "Successfully authenticated from Google account."
sign_in_and_redirect @user, event: :authentication
else
session["devise.google_data"] = request.env["omniauth.auth"]
.except("extra")
redirect_to new_user_registration_url,
alert: @user.errors.full_messages.join("n")
end
end
end
Ở đây, có một vài thông số có thể bạn cảm thấy khó hiểu, vì vậy mình sẽ giải thích như sau:
- request.env[“omniauth.auth”] : Tất cả thông tin được truy xuất từ Google bởi OmniAuth có sẵn dưới dạng băm tại đây
- Khi tìm thấy người dùng hợp lệ, họ có thể đăng nhập bằng một trong hai phương thức của Devise: sign_in hoặc sign_in_and_redirect, thông qua event: :authentication
- Trong trường hợp người dùng không còn tồn tại, sẽ lưu trữ dữ liệu OmniAuth trong session.
- Cuối cùng, sẽ chuyển hướng user trở lại form đăng ký.
Cấu hình Model
Sau khi xử lý ở Controller, chúng ta tiến hành triển khai tại Model User
def self.from_omniauth access_token
data = access_token.info
User.where(email: data["email"])
.first_or_create(email: data["email"],
password: Devise.friendly_token[0, 20],
provider: access_token[:provider],
uid: access_token[:uid])
end
Method này sẽ tìm người dùng theo các thuộc tính được truyền vào (tại hàm where). Sau đó, tiếp tục gọi hàm first_or_create, để nếu không tìm thấy user sẽ tạo user đó với các thuộc tính đã truyền vào, hoặc các thuộc tính khác được cấp. Password sẽ được tạo ngẫu nhiên bởi gem Devise.
Cấu hình view
Tại app/view/users/sessions/new.html.erb . Thêm:
<%- if devise_mapping.omniauthable? %>
<%- resource_class.omniauth_providers.each do |provider| %>
<%= link_to "Sign in with Google", omniauth_authorize_path(resource_name, provider), method: :post %>
<% end %>
<% end %>
Cấu hình đã xong, bây giờ thì rails s
và trải nghiệm thôi nào!
Nguồn: viblo.asia