OAuth2 và login qua Twitter
Bài đăng này đã không được cập nhật trong 3 năm
I. OAuth là gì?
1. Giới thiệu
Chắc hẳn nhiều bạn đã thấy những biểu tượng này khi đăng ký tài khoản tại một website nào đó
Và giờ ta không cần tạo một tài khoản mới nữa, chỉ cần có Account tại các ông lớn kia là đủ. Đó chính là tiện ích của OAuth đem lại (honho)
Vậy OAuth là gì?
OAuth (Open Authorization) là một phương thức chứng thực cho phép các ứng dụng của bên thứ ba có quyền truy cập tới một HTTP Service, thay mặt chủ sở hữu sử dụng tài nguyên của mình (tất nhiên cần phải có sự cho phép của người đó). Yêu cầu truy cập có thế đến từ website, mobile app,...
Ưu điểm:
- Tiện lợi: Không cần phải tạo tài khoản để đăng nhập mỗi khi sử dụng một web service hay application khác, đỡ phải nhớ nhiều (len)
- An toàn: Với OAuth 1.0 còn khá nhiều lỗi bảo mật nghiêm trọng, nhưng với OAuth2 thì đã khắc phục gần hết, người dùng không còn lo lắng khi phải đăng ký tài khoản ở một trang web không rõ nguồn gốc xuất xứ. (yaoming)
2. Một số khái niệm cơ bản
Roles
Với OAuth2, về cơ bản sẽ chia làm 4 roles chính:
- Resource Owner: chủ tài nguyên.
- Resource Server: server lưu trữ tài nguyên, vd như các ông lớn Google, Facebook, Twitter,..
- Client: Người dùng gửi request để truy cập thông qua website hoặc mobile app.
- Authorization Server: Server cung cấp
token
cho client. Token này sẽ được trả về và sử dụng khi có requets từ Client gửi tới.
Token
Là chuỗi ký tự ngẫu nhiên được tạo ra bởi Authorization Server và được cấp khi Client gửi request. Token có 2 loại:
- Access token: Token này được gửi từ Client như một parameters hoặc headers tới Resource Server, lifetime của nó được định nghĩa bởi Authorization Server.
- Refresh token: Song hành cùng với Access token nhưng nó chỉ đơn thuần được gửi để renewing Access token khi lifetime hết đát.
3. Work flow
Ví dụ ta có roles trong trường hợp như sau:
- Resource Owner: Mình
- Resource Server: Facebook server
- Client: Website Viblo
- Authorization Server: Facebook server
Kịch bản
- Từ Viblo, ta muốn login thông qua Facebook.
- Browser redirect tới trang chứng thực của Facebook (Authorization Server).
- Nếu ta cho phép truy cập, browser sẽ redirect ta về Viblo cùng với Access Token trên URI. Ví dụ như callback: http://viblo.asia/auth/callback&access_token=MynBTzUGYX8bHTnyLpZ4
- Access token này sẽ được client lấy và sử dụng khi truy cập tới Facebook lấy tài nguyên. Ví dụ: https://graph.facebook.com/me?access_token=MynBTzUGYX8bHTnyLpZ4
- Facebook dựa vào Token, nhận ra là thanh niên đã đăng ký trước đó, cho phép truy cập và trả về dữ liệu.
Về cơ bản là như vậy (yaoming).
Để hiểu rõ hơn, bạn có thể truy cập tới bài viết của anh Tùng về OAuth2, nó rất chi tiết.
II. Sử dụng OAuth2 để login qua Twitter
Dưới đây ta sẽ Demo rails app login qua Twitter bằng OAuth2 (len)
Bài viết dưới đây sử dụng
- Rails 4.1.4
- Mysql 5.6.27
- Ruby 2.1.4
Roles
- Resource owner: Yourself
- Resource server: Twitter server
- Client: Rails app.
- Authorization Server: Twitter
Các bước thực hiện
- Khởi tạo rails app, config và add gem cần thiết.
- Đăng ký API với Twitter.
- Add key mà Twitter cung cấp vào app.
- Điều hướng login tới đúng callback.
- Xử lý dữ liệu trả về (tạo session, save user).
1. Khởi tạo
Tạo một rails application mới
rails new social
Thêm bootstrap
cho đẹp trai (yaoming)
gem "bootstrap-sass"
# stylesheets/application.scss
@import "bootstrap-sprockets";
@import "bootstrap";
@import 'bootstrap/theme';
Chỉnh layout
<nav class="nav navbar-inverse">
<div class="container" >
<div class="navbar-header">
<%= link_to "Social", root_path, class: "navbar-brand" %>
</div>
<div id="navbar">
<ul class="nav navbar-nav">
<li><%= link_to 'Twitter', '/auth/twitter' %></li>
</ul>
</div>
</div>
</nav>
<div class="container">
<% flash.each do |message_type, message| %>
<div class="alert alert-<%= message_type %>">
<%= message %>
</div>
<% end %>
<%= yield %>
</div>
Tạo controller mới tên HomeController
rails g controller home index
Chỉnh root
tới method index
trong HomeController
làm trang chủ
root "home#index"
Setup xong (dance2)
2. Login thông qua Twitter
Ta sử dụng thêm gem OmniAuth
để kết nối với Twitter dễ dàng hơn
gem 'omniauth-twitter'
Tạo file để config.
# config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
provider :twitter, ENV['TWITTER_KEY'], ENV['TWITTER_SECRET']
end
Ở đây ta thấy có 2 biến là ENV['TWITTER_KEY']
và ENV['TWITTER_SECRET']
là key của Twitter cung cấp cho website sử dụng để đăng nhập thông qua nó.
Để lấy key ta truy cập ta thực hiện những bước sau:
- Truy cập apps.twitter.com
- Login và chọn Create New App
- Điền thông tin vào form đăng ký
- Mục Callback URL sẽ =
Domain
+/auth/twitter/callback/
(nếu ở localhost thì thay bằng127.0.0.1:3000
) - Sau khi đăng ký xong, mở tab Keys and Access Tokens ở đây ta sẽ thấy mục API Key và API Secret, chính là tương ứng với 2 biến
ENV['TWITTER_KEY']
vàENV['TWITTER_SECRET']
đã khai báo ở trên.
Add routes cho callback tương ứng với Callback URL đã khai báo ở trên:
get '/auth/:provider/callback', to: 'sessions#create'
delete '/logout', to: 'sessions#destroy'
Tạo controller và method sẽ xử lý request
class SessionsController < ApplicationController
def create
end
end
Thế là đã kết nối xong (honho).
Sau khi gửi request, thông tin được Twitter API trả về được lưu trong biến request.env['omniauth.auth']
có dạng như sau:
{
:provider => "twitter",
:uid => "123456",
:info => {
:nickname => "johnqpublic",
:name => "John Q Public",
:location => "Anytown, USA",
:image => "http://si0.twimg.com/sticky/default_profile_images/default_profile_2_normal.png",
:description => "a very normal guy.",
:urls => {
:Website => nil,
:Twitter => "https://twitter.com/johnqpublic"
}
},
:credentials => {
:token => "a1b2c3d4...", # The OAuth 2.0 access token
:secret => "abcdef1234"
},
:extra => {
:access_token => "", # An OAuth::AccessToken object
:raw_info => {
:name => "John Q Public",
:listed_count => 0,
:profile_sidebar_border_color => "181A1E",
:url => nil,
:lang => "en",
:statuses_count => 129,
:profile_image_url => "http://si0.twimg.com/sticky/default_profile_images/default_profile_2_normal.png",
:profile_background_image_url_https => "https://twimg0-a.akamaihd.net/profile_background_images/229171796/pattern_036.gif",
:location => "Anytown, USA",
:time_zone => "Chicago",
:follow_request_sent => false,
:id => 123456,
:profile_background_tile => true,
:profile_sidebar_fill_color => "666666",
:followers_count => 1,
:default_profile_image => false,
:screen_name => "",
:following => false,
:utc_offset => -3600,
:verified => false,
:favourites_count => 0,
:profile_background_color => "1A1B1F",
:is_translator => false,
:friends_count => 1,
:notifications => false,
:geo_enabled => true,
:profile_background_image_url => "http://twimg0-a.akamaihd.net/profile_background_images/229171796/pattern_036.gif",
:protected => false,
:description => "a very normal guy.",
:profile_link_color => "2FC2EF",
:created_at => "Thu Jul 4 00:00:00 +0000 2013",
:id_str => "123456",
:profile_image_url_https => "https://si0.twimg.com/sticky/default_profile_images/default_profile_2_normal.png",
:default_profile => false,
:profile_use_background_image => false,
:entities => {
:description => {
:urls => []
}
},
:profile_text_color => "666666",
:contributors_enabled => false
}
}
}
Điều ta cần làm bây giờ là dựa vào data trả về để khởi tạo Sessions & Save User.
Trong một đống data trả về thế kia, ta chỉ lựa chọn một số thông tin cho Demo này.
provider
: Twitteruid
: Id của Username
: Tên của Userlocation
image
: Avatar URLurl
: Profile url
Generate migration
rails g model User provider:string uid:string name:string location:string image_url:string url:string
Bên phía model User
ta tạo một method để lưu trữ lại thông tin User vào DB khi đăng nhập lần đầu tiên
def self.from_omniauth auth_hash
user = find_or_create_by(uid: auth_hash['uid'], provider: auth_hash['provider'])
user.name = auth_hash['info']['name']
user.location = auth_hash['info']['location']
user.image_url = auth_hash['info']['image']
user.url = auth_hash['info']['urls']['Twitter']
user.save!
user
end
Từ agrument auth_hash
là thông tin User được trả về sau khi login qua Twitter, ta kiểm tra trong DB User này đã tồn tại chưa, nếu chưa thì tạo mới user.
Xử lý tạo Sessions
class SessionsController < ApplicationController
def create
begin
@user = User.from_omniauth(request.env['omniauth.auth'])
session[:user_id] = @user.id
flash[:success] = "Welcome, #{@user.name}!"
rescue
flash[:warning] = "Got errors when authenticate"
end
redirect_to root_path
end
end
Tạo biến current_user để xác thực User đã login hay chưa
# application_controller.rb
private
def current_user
@current_user ||= User.find_by(id: session[:user_id])
end
helper_method :current_user
Xử lý hiển thị trên View khi User đã login
<% if current_user %>
<ul class="nav navbar-nav pull-right">
<li><%= image_tag current_user.image_url, alt: current_user.name %></li>
<li><%= link_to 'Log Out', logout_path, method: :delete %></li>
</ul>
<% else %>
<ul class="nav navbar-nav">
<li><%= link_to 'Twitter', '/auth/twitter' %></li>
</ul>
<% end %>
Destroy
sessions khi logout
def destroy
if current_user
session.delete(:user_id)
flash[:success] = 'See you!'
end
redirect_to root_path
end
Kết quả màn hình trang chủ
Sau khi click vào nút login, trang sẽ được redirect tới Twitter để chứng thực quyền đăng nhập
Nhập Username và password của tài khoản trên Twitter vào, hệ thống sẽ lưu thông tin User, tạo Session và redirect về trang chủ
Giờ thông tin đã lấy đấy đủ, ta sẽ show ra ở trang index
<% if current_user %>
<div class="panel panel-default">
<div class="panel-body">
<ul>
<li><strong>Name:</strong> <%= current_user.name %></li>
<li><strong>Provider:</strong> <%= current_user.provider %></li>
<li><strong>uID:</strong> <%= current_user.uid %></li>
<li><strong>Location:</strong> <%= current_user.location %></li>
<li><strong>Avatar URL:</strong> <%= current_user.image_url %></li>
<li><strong>URL:</strong> <%= current_user.url %></li>
</ul>
</div>
</div>
<% end %>
Kết quả
Source
Github: https://github.com/NguyenTanDuc/twitter-oauth2
Nguồn tham khảo
All rights reserved