about 1 year ago

這一篇主要談了解sails-generate-auth的源碼,但因為sails generator基本上就是直接幫你產生Model/Controller etc.的檔案,所以直接看/template下的所以程式碼
使用此模組最大好處在於 整合Sails框架與Passport認證機制,包含Local(帳密)與第三方OAuuth2註冊登入機制,他還會將兩者做連結,例如說使用者先註冊了帳密,再用FB登入發現Email相同,此模組會自動連結兩者視為相同使用者(反之不成立!)
所以基本上會

  1. 登入/註冊頁面呈現
  2. Passport Strategy設定
  3. Controller與Model的建立,將資料存入資料庫
  4. Passport的註冊登入機制
  5. 帳號連結

首先看到 /template/api/controllers/AuthController.js
其中幾個 login/ register/ logout都只有基本邏輯與繪製頁面,但特別留意provider/callback,這兩者都有使用到定義於services的passport,provider作為第三方OAuth認證的進入函式,而callback很明顯就是完成認證後的使用者資料處理邏輯的函式。

接著看到 /template/api/models底下User.js和Passport.js;
User.js簡單定義使用者的資料格式,User可對應到多個Passport;
Passport.js中主要紀錄
protocol:誰提供認證,是local還是oauth2等
provider:OAuth認證的第三方服務,是FB還是G+等
user:Passport一定要對應到一個使用者
其他的token/password欄位就都蠻好理解的

重頭戲在/template/services底下,複雜的主業務邏輯都定義在此,
/protocols資料夾下有多個local.js/ oauth.js/ oauth2.js等,主要定義觸發登入/註冊後如何處理資料的邏輯
例如說在local.js中,就會有register function,先檢查email/password欄位是否正確、帳號是否已存在等等,接著就User.create(...)創建新的使用者資料;
login function邏輯也很好理解,另外還有一個connect function,這會先檢查Passport是否有存在使用者;
如果是看oauth2.js,裡頭定義的是第三方OAuth服務Callback的處理方式,此時特別留意identifier為Callback中profile.id

接著看passport.js,共有將近四百行程式碼,這是最關鍵所在
首先載入剛才定義的/protocols,接著定義以下函式

  1. endpoint
    在AuthController.js中provider function是第三方OAuth服務的進入點,裡頭的唯一函式就是passport.endpoint(),這裡主要是Request中呼叫的strategy是否有被定義,沒有的話則redirect到登入頁面,反之繼續
    他最後呼叫this.authenticate(provider, options)(req, res, req.next);,如果你曾在Express中用過passport,這就是
    router.get('/auth/facebook', passport.authenticate('facebook', {scope: ['public_profile', 'user_friends']}));
    
    剩下的就進入Passport邏輯中
  2. callback
    在callback function中,最主要針對action = req.param('action');做分類處理,主要有login/register/connect/disconnect
  3. connect
    此段註解中解釋認證的流程,
    "找出provider和identifier" -> "找出相對應的Passport",接著分成兩部分
    a. 假設使用者尚未登入
    -> 如果Passport不存在,創建新使用者與新的Passport並兩者關聯(使用者第一次使用)
    -> 如果Passport存在,代表已經註冊過,找出User
    b. 假設使用者已經登入
    -> 假設Passport不存在,創建新的Passport並關聯User
    -> 如果Passport存在,什麼事都不用發生
  4. disconnect 刪除與User關聯的Passport

至於passport的strategy與第三方OAuth服務的API Key都是定義在/template/config/passport.js底下,/template/config/locales/en.json則定義錯誤訊息,例如帳號不存在、密碼錯誤等等,此Library習慣用req.flash()取出佔存在session的錯誤訊息,接著用page render方式顯示。

最後記得在 /config/routes

'get /login': 'AuthController.login',
'post /logout': 'AuthController.logout',
'get /register': 'AuthController.register',

'post /auth/local': 'AuthController.callback',
'post /auth/local/:action': 'AuthController.callback',

'get /auth/:provider': 'AuthController.provider',
'get /auth/:provider/callback': 'AuthController.callback',
'get /auth/:provider/:action': 'AuthController.callback',

還有插入policy,這些generator都會處理好,不需要特別調整。

使用

在頁面上,表單按鈕中“登入” -> POST /auth/local,"註冊" -> POST /auth/local/register
"FB登入" -> GET /auth/facebook
進入後,在AuthController.callback() -> passport.endpoint()中用req.param('action')req.param('provider')再分流 -> passport.callback()處理

← Nodejs - oauth2-provider源碼解析 NodeJS - 使用fs打造版本控制,更新檔名與內容 →
 
comments powered by Disqus