首先看看有哪些設定檔。(這裡可能講的有些零亂,不過先看過去,等把下面流程的部份對照一下就應該蠻清楚了。)
在 config/dependencies.rb 可以看到下面這三行:
dependency "merb-auth-core", merb_gems_versionMerb-Auth 和 Merb 一樣,依據必要性的不同,分成三個部份。
dependency "merb-auth-more", merb_gems_version
dependency "merb-auth-slice-password", merb_gems_version
- merb-auth-core 包含了最基本的功能,像是上一篇講到的 session.user 或是 ensure_authenticated 這些做登入一定會用到的東西。
- merb-auth-more 包含了一些好用的功能,像是已經寫好的三種登入方式(http-basic / password / openid),登入完可以導回原本要去的頁面的 redirect_back_or 等等。
- merb-auth-slice-password 則是一個 slice 。slice 是 merb 的一個超強大功能,可以把他想成是一個小型的 app,讓你可以隨意的整合進其它的 app 裡面。我們上一篇,在我們還沒有寫 login form 的 view (app/views/exceptions/unauthenticated.html.erb) 時 ,用的就是這個 slice 已經幫我們寫好的!
接下來另一個重要的設定檔是 merb/merb-auth/setup.rb:
# Merb::Plugins.config[:"merb-auth"][:login_param] = :email這兩行原本是被 comment 起來。它們是用來設定登入時所用的欄位名稱。預設是用 login/password,不過大家應該比較喜歡 username/password 吧!
# Merb::Plugins.config[:"merb-auth"][:password_param] = :my_password_field_name
Merb::Authentication.user_class = User這行設定的是登入物件的 class 。所謂的登入物件就是你要用什麼物件來代表登入的這個人。像有人會喜歡用 Person / Account 之類的。
require 'merb-auth-more/mixins/salted_user'這兩行將 salted password 的邏輯加到了剛剛設定的登入物件 class 裡面。如果你去翻一下上一篇我們的程式,在 app/models/user.rb 裡,你會看到並沒有設定 crypted_password,salt 等欄位,可是生出來的 User object 卻有,就是因為這兩行啦!
Merb::Authentication.user_class.class_eval{ include Merb::Authentication::Mixins::SaltedUser }
class Merb::Authentication這幾行是告訴 Merb-Auth 怎麼從 session 中取得的東西轉換成登入物件(fetch_user),或是怎麼從登入物件轉換成 session 中所存的東西(store_user)。因為有這個設定的關係,你的登入物件可以和 database 完全沒有關係,甚至只是一個 Boolean 都可以(就是只有登入和沒登入兩種情況,不管登入的人是誰)。預設的 fetch_user 是用 datamapper 去資料庫拿物件出來,如果你用的是 AR 就要改這裡了。
def fetch_user(session_user_id)
Merb::Authentication.user_class.get(session_user_id)
end
def store_user(user)
user.nil? ? user : user.id
end
end
還有一另一個設定檔 merb/merb-auth/strategies.rb
Merb::Authentication.activate!(:default_password_form)這裡是將 default_password_form 和 default_basic_auth 這兩個登入的方式啟動。如果你想用別的認證方式,像是 openid / ldap / AD 之類的,就可以寫在這裡。
Merb::Authentication.activate!(:default_basic_auth)
接下來我們來解釋一下整個登入的流程。
當我們要去看一個需要登入才能看的頁面時(例子中的 /hello/index 或是 /hello/wazzap ),Merb-Auth 會先看看 session[:user] 是否有東西,有的話表示已經登入了。如果沒有登入的話,它會用各種的方式去登入。這些方式被稱為 Strategies,也就是在 merb/merb-auth/strategies.rb 裡設定的東西。
這些 Strategy 可以取得 Request 的各種參數(cookie/session/url/route/params...),用它們來判斷這個 session 是不是可以成功的登入。當某一個 Strategy 成功時,Merb-Auth 會用設定的 store_user 將 user 存進 session 裡,這樣下一次 request 再來時就可以直接跳過登入的過程了。
當所有的 Strategies 都失敗的時候,Merb-Auth 並不像 Rails 一般的做法,丟一個 302 redirect 到登入的 action 去,而是直接丟 401 Unauthorized 錯誤出來。(你可以用 firebug 去看他的 response status code。別告訴我你沒裝這個 WebDeveloper 最好的朋友。)
那為什麼 401 錯誤會有個 login 的 form 呢?這就是 merb 好玩的地方了!當程式執行中發生的 Exception,都會被 merb 自己 catch 起來,幫他放一個 status code ,然後 re-route 到 app/controllers/exceptions.rb 的某個 action 去。 Merb-Auth 發出來的 Exception 是自己定義的 Unauthenticated,它的 status code 401 ,而對應到的 action 就是 Exceptions#unauthenticated 了。
這個 controller 和一般的 controller 沒什麼兩樣,也可以用 layout,可以用 before/after filter,可以用 template。merb-auth-slice-password 貼心的(或者應該說是雞婆的)幫我們準備了 Exceptions#unauthenticated 這個 aciton 還有它的 view 。所以你如果要改變登入 form 樣子,就自己寫 app/controllers/exceptions.rb 的 unauthenticated 這個 method 和 app/views/exceptions/unauthenticated.html.erb 這個 file 吧。
這一篇我們說明了 Merb-Auth 大致的原理,下一篇就幫我們的 Hello 加上 OpenID 的支援。
沒有留言:
張貼留言