代登入或是授權登入(Authentication)這幾年在網站或是app開發上這幾年越來越重要
有些商家或許是想減少使用者需要額外創建帳號的負擔
但是事實上!!!
各種社群網站仍然彼此各自擁有自己的忠實用戶,
也有些用戶跟小編朋友一樣, 並不太喜歡用這些帳號登入(這部分可先不談)
這篇教學是讓有興趣利用Ruby on rails 4.0.0 開發Facebook 代登入的朋友可以參考的入門教學
有興趣的版友請不要錯過!!
附註: 本文假設讀者已經有安裝好ruby on rails, 如果不知道如何安裝的版友可以先點擊參考這篇
(文章最末有github上的載點)
有些商家或許是想減少使用者需要額外創建帳號的負擔
但是事實上!!!
各種社群網站仍然彼此各自擁有自己的忠實用戶,
也有些用戶跟小編朋友一樣, 並不太喜歡用這些帳號登入(這部分可先不談)
這篇教學是讓有興趣利用Ruby on rails 4.0.0 開發Facebook 代登入的朋友可以參考的入門教學
有興趣的版友請不要錯過!!
附註: 本文假設讀者已經有安裝好ruby on rails, 如果不知道如何安裝的版友可以先點擊參考這篇
(文章最末有github上的載點)
Part I. 前置作業
註記: 本文的環境是在Mac OSX 10.8.4下運行
一切都使用terminal 終端機運行
1. 版友需要先安裝幾個open source, 用以下指令下載即可
git clone https://github.com/shouian/devise.git
git clone https://github.com/intridea/omniauth.git
git clone https://github.com/shouian/omniauth-facebook.git
git clone https://github.com/shouian/oauth2
git clone https://github.com/stevegraham/certified.git
2. 下載好以後, 還需要安裝所有工具 (需要有 gem 的安裝工具, 在安裝好ruby時理論上也會一起安裝好gem 如果不知道怎麼安裝的可以參考這篇), 在終端機依序輸入以下command
gem install devise
gem install omniauth
gem install omniauth-facebook
gem install oauth2
gem install certified
3. 準備申請Facebook 應用程式
前往Facebook開發網址: https://developers.facebook.com/
先申請完一個帳號以後, 到右上方的 "Apps "
然後點選 “創建新的應用程式”
會出現以下畫面
註記: 本文的環境是在Mac OSX 10.8.4下運行
一切都使用terminal 終端機運行
1. 版友需要先安裝幾個open source, 用以下指令下載即可
git clone https://github.com/shouian/devise.git
git clone https://github.com/intridea/omniauth.git
git clone https://github.com/shouian/omniauth-facebook.git
git clone https://github.com/shouian/oauth2
git clone https://github.com/stevegraham/certified.git
2. 下載好以後, 還需要安裝所有工具 (需要有 gem 的安裝工具, 在安裝好ruby時理論上也會一起安裝好gem 如果不知道怎麼安裝的可以參考這篇), 在終端機依序輸入以下command
gem install devise
gem install omniauth
gem install omniauth-facebook
gem install oauth2
gem install certified
3. 準備申請Facebook 應用程式
前往Facebook開發網址: https://developers.facebook.com/
先申請完一個帳號以後, 到右上方的 "Apps "
然後點選 “創建新的應用程式”
會出現以下畫面
4. 記住你的App ID與App Secret 他是辨認你這款app的身分證, 不論是在行動裝置上或網頁上都需要這兩個資料的key才能獲得Facebook有關的permission (詳細部分之後會介紹)
5. 最後記得設定你的redirect URL, 這是代表當你的使用者確認所有的使用權以後會重新導回的網頁
這邊我們使用: http://localhost:3000
(參考下圖)
5. 最後記得設定你的redirect URL, 這是代表當你的使用者確認所有的使用權以後會重新導回的網頁
這邊我們使用: http://localhost:3000
(參考下圖)
Part II. 實際開始Coding
註記: 以下紅色內容都是terminal終端機需要輸入的command
1. 產生一個新專案吧! 把它叫做omniauth-tutorial (指令如下)
rails new omniauth-tutorial
2. 修改Gemfile
vi Gemfile 增加以下內容, 這樣才能載入已經裝在電腦裡的Opensource
# Use Omni-Auth
gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'oauth2'
gem 'certified'
3.安裝這些opensource在專案內: bundle install
4. 建立一個 omniauth.rb檔案, 是所有認證要用的檔案 vi config/initializers/omniauth.rb
修改內容如下:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, '你的App ID', '你的App Secret', :client_options => {:ssl => {:ca_path => '/etc/ssl/certs'}}
end
這邊就是放入你的專案有需要提供代登入認證的服務provider
比如說facebook, twitter, google+,....後面則是放入ssl認證
要注意在Ruby on Rails 4.0.0的時候記得要安裝certified這個opensource
不然會有ssl認證錯誤的結果喔!!
至此, 環境才初步架設完成
5. 建立login的頁面: rails generate controller sessions new create failure
這樣會在sessions_controller中底下有對應的new, create, failure 的狀態method
6. 修改對應的頁面在router上的情況: vi config/routes.rb
OmniauthTutorial::Application.routes.draw do
get '/login', :to => 'sessions#new', :as => :login
get '/logout', :to => 'sessions#destory'
match '/auth/:provider/callback', :to => 'sessions#create'
match '/auth/failure', :to => 'sessions#failure'
end
解釋如下:
i. get '/login', :to => 'sessions#new', :as => :login
這段是做登入facebook的頁面連接
ii. match '/auth/:provider/callback', :to => 'sessions#create'
是在修改provider的回呼函數, 當使用者同意授權以後, provider就會將app重新導向回設定好的url, 我們再將它導入到create的頁面
這樣我們就能取得使用者的data
iii.match '/auth/failure', :to => 'sessions#failure'
會在導向失敗, 或是發生其他錯誤時導入到failure的頁面
iv. get '/logout', :to => 'sessions#destory'
原本我想加入在另一個頁面叫做destroy, 不過這邊只是寫好玩的沒有實際用途
可以在登入logout頁面時清空所有session
要使用的話在一開始的時候必須要把command 改成 rails generate controller sessions new create failure destroy
7. 建立使用者的紀錄Data (User Model): rails generate model User name:string email:string
本範例我們只記錄使用者名稱與email
8. 建立完成使用者的model後, 我們要建立授權(authoriation)的model : rails generate model Authorization provider:string uid:string user_id:integer
因為現行採用的授權機制通常都只需要uid, 跟授權者(provider)的名稱
之後只需要在omniauth.rb內增加其他provider(例如twitter, google+)以及適當的補充一些opensource修正就能完成其他社群網站的登入授權了
完成以後做以下修改
i. vi app/models/user.rb
增加以下內容
has_many :authorizations
validates :name, :email, :presence => true
ii. vi app/models/authorization.rb
增加以下內容
belongs_to :user
validates :provider, :uid, :presence => true
9. 把data table 跟model 們建立連結: rake db:migrate
不執行這一段的話會出現錯誤 "Could not find table" (原文教學有錯誤)
10.接下來要修正我們的session_controller 來判斷是要註冊使用者(sign up)或是標記他們已經登入過(logs user)
輸入以下command: vi app/controllers/sessions_controller.rb
我們先修正 create 的method 如下
def create
auth_hash = request.env['omniauth.auth']
@authorization = Authorization.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
if @authorization
render :text => "Welcome back #{@authorization.user.name}! You have already signed up."
else
user = User.new :name => auth_hash["info"]["name"], :email => auth_hash["info"]["email"]
user.authorizations.build :provider => auth_hash["provider"], :uid => auth_hash["uid"]
user.save
render :text => "Hi #{user.name}! You've signed up."
end
end
這段邏輯是這樣子的:
(i) 我們先確認授權(auth_hash)對於這個服務的provider或是uid是否存在, 如果其中一個存在, 我們就歡迎他登入(用render :text)
(ii) 如果兩者皆不存在, 我們就把他們註冊起來, 建立一個新的user (User.new 的method), 把uid 跟provider都提供給auth_hash變數
再用user.save的method儲存起來
有關Multiple provider的部分, 會在另一篇教學內提到
11. 為了讓以上的code能夠支援multiple provider 我們還要修改authorization.rb跟user.rb的內容
(i)修改user: vi app/models/user.rb
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :authorizations
validates :name, :email, :presence => true
def add_provider(auth_hash)
# Check if the provider already exists, so we don't add it twice
unless authorizations.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
Authorization.create :user => self, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
end
end
如果使用者還沒有讓provider跟這個帳號取得聯繫, 我們用Authorization.create建立聯結!
(ii)修改auth: vi app/models/authorization.rb
class Authorization < ActiveRecord::Base
attr_accessible :provider, :uid, :user_id, :user
belongs_to :user
validates :provider, :uid, :presence => true
def self.find_or_create(auth_hash)
unless auth = find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
user = User.create :name => auth_hash["info"]["name"], :email => auth_hash["info"]["email"]
auth = create :user => user, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
auth
end
end
這段程式碼中, 我們企圖去找到符合這個request的授權, 如果都沒找到, 我們用User.create的方式建立新user
12. 其它可以做但目前不必要做的事情.....
增加destroy 跟fail 的method: vi app/controllers/sessions_controller.rb
def destroy
session[:user_id] = nil
render :text => "You've logged out"
end
def failure
render :text => "Sorry, but you didn't allow access to our app!"
end
這樣用來處理登入失敗或登出時的狀態, 上傳版本的code內沒有包含destroy的部分需要注意
13. 最後需要做的事情, 顯示連結在畫面: vi app/views/sessions/new.html.erb
<h1>Sessions#new</h1>
<p>Find me in app/views/sessions/new.html.erb</p>
<%= link_to "Connect with Facebook", "/auth/facebook" %>
14. 完成的時候會看到以下畫面....
註記: 以下紅色內容都是terminal終端機需要輸入的command
1. 產生一個新專案吧! 把它叫做omniauth-tutorial (指令如下)
rails new omniauth-tutorial
2. 修改Gemfile
vi Gemfile 增加以下內容, 這樣才能載入已經裝在電腦裡的Opensource
# Use Omni-Auth
gem 'devise'
gem 'omniauth'
gem 'omniauth-facebook'
gem 'oauth2'
gem 'certified'
3.安裝這些opensource在專案內: bundle install
4. 建立一個 omniauth.rb檔案, 是所有認證要用的檔案 vi config/initializers/omniauth.rb
修改內容如下:
Rails.application.config.middleware.use OmniAuth::Builder do
provider :facebook, '你的App ID', '你的App Secret', :client_options => {:ssl => {:ca_path => '/etc/ssl/certs'}}
end
這邊就是放入你的專案有需要提供代登入認證的服務provider
比如說facebook, twitter, google+,....後面則是放入ssl認證
要注意在Ruby on Rails 4.0.0的時候記得要安裝certified這個opensource
不然會有ssl認證錯誤的結果喔!!
至此, 環境才初步架設完成
5. 建立login的頁面: rails generate controller sessions new create failure
這樣會在sessions_controller中底下有對應的new, create, failure 的狀態method
6. 修改對應的頁面在router上的情況: vi config/routes.rb
OmniauthTutorial::Application.routes.draw do
get '/login', :to => 'sessions#new', :as => :login
get '/logout', :to => 'sessions#destory'
match '/auth/:provider/callback', :to => 'sessions#create'
match '/auth/failure', :to => 'sessions#failure'
end
解釋如下:
i. get '/login', :to => 'sessions#new', :as => :login
這段是做登入facebook的頁面連接
ii. match '/auth/:provider/callback', :to => 'sessions#create'
是在修改provider的回呼函數, 當使用者同意授權以後, provider就會將app重新導向回設定好的url, 我們再將它導入到create的頁面
這樣我們就能取得使用者的data
iii.match '/auth/failure', :to => 'sessions#failure'
會在導向失敗, 或是發生其他錯誤時導入到failure的頁面
iv. get '/logout', :to => 'sessions#destory'
原本我想加入在另一個頁面叫做destroy, 不過這邊只是寫好玩的沒有實際用途
可以在登入logout頁面時清空所有session
要使用的話在一開始的時候必須要把command 改成 rails generate controller sessions new create failure destroy
7. 建立使用者的紀錄Data (User Model): rails generate model User name:string email:string
本範例我們只記錄使用者名稱與email
8. 建立完成使用者的model後, 我們要建立授權(authoriation)的model : rails generate model Authorization provider:string uid:string user_id:integer
因為現行採用的授權機制通常都只需要uid, 跟授權者(provider)的名稱
之後只需要在omniauth.rb內增加其他provider(例如twitter, google+)以及適當的補充一些opensource修正就能完成其他社群網站的登入授權了
完成以後做以下修改
i. vi app/models/user.rb
增加以下內容
has_many :authorizations
validates :name, :email, :presence => true
ii. vi app/models/authorization.rb
增加以下內容
belongs_to :user
validates :provider, :uid, :presence => true
9. 把data table 跟model 們建立連結: rake db:migrate
不執行這一段的話會出現錯誤 "Could not find table" (原文教學有錯誤)
10.接下來要修正我們的session_controller 來判斷是要註冊使用者(sign up)或是標記他們已經登入過(logs user)
輸入以下command: vi app/controllers/sessions_controller.rb
我們先修正 create 的method 如下
def create
auth_hash = request.env['omniauth.auth']
@authorization = Authorization.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
if @authorization
render :text => "Welcome back #{@authorization.user.name}! You have already signed up."
else
user = User.new :name => auth_hash["info"]["name"], :email => auth_hash["info"]["email"]
user.authorizations.build :provider => auth_hash["provider"], :uid => auth_hash["uid"]
user.save
render :text => "Hi #{user.name}! You've signed up."
end
end
這段邏輯是這樣子的:
(i) 我們先確認授權(auth_hash)對於這個服務的provider或是uid是否存在, 如果其中一個存在, 我們就歡迎他登入(用render :text)
(ii) 如果兩者皆不存在, 我們就把他們註冊起來, 建立一個新的user (User.new 的method), 把uid 跟provider都提供給auth_hash變數
再用user.save的method儲存起來
有關Multiple provider的部分, 會在另一篇教學內提到
11. 為了讓以上的code能夠支援multiple provider 我們還要修改authorization.rb跟user.rb的內容
(i)修改user: vi app/models/user.rb
class User < ActiveRecord::Base
attr_accessible :email, :name
has_many :authorizations
validates :name, :email, :presence => true
def add_provider(auth_hash)
# Check if the provider already exists, so we don't add it twice
unless authorizations.find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
Authorization.create :user => self, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
end
end
如果使用者還沒有讓provider跟這個帳號取得聯繫, 我們用Authorization.create建立聯結!
(ii)修改auth: vi app/models/authorization.rb
class Authorization < ActiveRecord::Base
attr_accessible :provider, :uid, :user_id, :user
belongs_to :user
validates :provider, :uid, :presence => true
def self.find_or_create(auth_hash)
unless auth = find_by_provider_and_uid(auth_hash["provider"], auth_hash["uid"])
user = User.create :name => auth_hash["info"]["name"], :email => auth_hash["info"]["email"]
auth = create :user => user, :provider => auth_hash["provider"], :uid => auth_hash["uid"]
end
auth
end
end
這段程式碼中, 我們企圖去找到符合這個request的授權, 如果都沒找到, 我們用User.create的方式建立新user
12. 其它可以做但目前不必要做的事情.....
增加destroy 跟fail 的method: vi app/controllers/sessions_controller.rb
def destroy
session[:user_id] = nil
render :text => "You've logged out"
end
def failure
render :text => "Sorry, but you didn't allow access to our app!"
end
這樣用來處理登入失敗或登出時的狀態, 上傳版本的code內沒有包含destroy的部分需要注意
13. 最後需要做的事情, 顯示連結在畫面: vi app/views/sessions/new.html.erb
<h1>Sessions#new</h1>
<p>Find me in app/views/sessions/new.html.erb</p>
<%= link_to "Connect with Facebook", "/auth/facebook" %>
14. 完成的時候會看到以下畫面....
這時候看到你的終端機畫面應該是如下
能夠看到有SQL的語法等!
能夠看到有SQL的語法等!
15. 如果原本的程式碼要改成支援multiple provider,
只需要把session_controller中的create的action 修改如下就可以了!
(當然, 還需要到 config/routes.rb 增加 其他provider的App Key與Secret)
def create
auth_hash = request.env['omniauth.auth']
if session[:user_id]
User.find(session[:user_id]).add_provider(auth_hash)
render :text => "You can now login using #{auth_hash["provider"].capitalize} too!"
else
# Log him in or sign him up
auth = Authorization.find_or_create(auth_hash)
# Create the session
session[:user_id] = auth.user.id
render :text => "Welcome #{auth.user.name}!"
end
end
只需要把session_controller中的create的action 修改如下就可以了!
(當然, 還需要到 config/routes.rb 增加 其他provider的App Key與Secret)
def create
auth_hash = request.env['omniauth.auth']
if session[:user_id]
User.find(session[:user_id]).add_provider(auth_hash)
render :text => "You can now login using #{auth_hash["provider"].capitalize} too!"
else
# Log him in or sign him up
auth = Authorization.find_or_create(auth_hash)
# Create the session
session[:user_id] = auth.user.id
render :text => "Welcome #{auth.user.name}!"
end
end
各位辛苦了!!!
小編也總算打完了(泣....)
對本篇文章有興趣的版友, 可以直接到github上下載噢!
Githhub位置:
https://github.com/shouian/OmniauthWithFacebookLogin
本篇有許多沒有解釋清楚的部分
接下來也會一一補充完整供大家參考!!!