Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方帳號登入整合的問題,那麼在擷取到使用者資料之後呢?整合多個社交帳號,該如何綁定同一個帳號?本篇就讓我們來探討一下整合登入的那點事。
起初
起初,當我們只需要整合單個社交登入時,我們可能會為了快速的完成任務簡單粗暴的在使用者模型中加入 open_id 或者 github_id 類似的屬性,那麼在資料庫中,我們需要在表中添加相應的欄位。這是可以快速有效完成任務的做法。
但是,當更多的需求來臨時,要求我們額外的整合一種或者多種社交登入,那該怎麼辦?難道我們還要任性的在表結構中添加相應的欄位?
Schema::table('users', function ($table) { $table->string('github_id'); $table->string('douban_id');});
這很明顯的違背了開放封閉原則,假如我們這麼做,那麼可以想象的當每多整合一種登入時,我們就需要對資料表結構做出一次修正,並且,在登入授權回調驗證時,還要增加一道整合驅動與欄位查詢匹配的工序。
那應該怎麼做?
設想
這麼想來,User 表是否承擔了過多的能力,它是否應該浪費自己的精力來管理這些社交標識?那不如我們安排 SocialiteUser 來專門系統管理使用者與社交帳號之間的關係?我們需要設計一種易擴充的方案來管理不同驅動的社交登入,那麼我們很容易的設計出這種表結構:
- socialite_users - id - user_id - driver - open_id
SocialiteUser 應該具有哪些職責?很顯然,它主要用來維護社交登入標識和使用者模型之間的關係。那麼它應該具有以下能力:
將社交登入賬戶綁定到使用者模型上
擷取匹配的使用者模型
以下為簡單的代碼示範:
where([ 'driver' => $driver, 'open_id' => $openid ])->first(); return $finder ? $finder->user : $finder; } /** * get related user model. * * @return /App/User||null */ public function user() { return $this->belongsTo('App\User'); } /** * Save a new record. * * @param $userId integer * @param $driver string * @param $id string * @return /App/SocialiteUser */ public function saveOne($userId, $driver, $id) { return $this->create([ 'user_id' => $userId, 'driver' => $driver, 'open_id' => $id ]); }}
使用
在授權登入流程中,使用者同意授權,第三方應用將重新導向到回調路由,回調路由中 Socialite 會主動請求擷取使用者資料,並將使用者的社交標識 ID 映射到 User 模型的 id 屬性上。
那麼我們就可以在回調路由中根據驅動標識和使用者相應的社交標識 ID 來匹配查詢庫中是否已存在綁定的使用者。如果存在那就直接使用匹配到的使用者登入,如果不存在,那麼就產生一個使用者,並為這個使用者附加社交賬戶資訊。然後使用新產生的賬戶登入。
redirect(); } public function handleProviderCallback($driver) { $user = Socialite::driver($driver)->user(); $model = new User(); $socialiteUser = new SocialiteUser(); $finder = $socialiteUser->getUser($driver, $user->id); if (! $finder) { $finder = $model->generateUserInstance(); $finder->save(); $socialiteUser->saveOne($finder->id, $driver, $user->id); } Auth::login($finder); return view('home'); }}
這樣看來,如果需求一種新的社交登入的整合,那麼完全不需要做出其它代碼的改動,直接配置驅動就可以了。
PS: 歡迎關注簡書 Laravel 專題,也歡迎 Laravel 相關文章的投稿 :),作者知識技能水平有限,如果你有更好的設計方案歡迎討論交流,如果有錯誤的地方也請批評指正,在此表示感謝謝謝 :)
回複內容:
Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方帳號登入整合的問題,那麼在擷取到使用者資料之後呢?整合多個社交帳號,該如何綁定同一個帳號?本篇就讓我們來探討一下整合登入的那點事。
起初
起初,當我們只需要整合單個社交登入時,我們可能會為了快速的完成任務簡單粗暴的在使用者模型中加入 open_id 或者 github_id 類似的屬性,那麼在資料庫中,我們需要在表中添加相應的欄位。這是可以快速有效完成任務的做法。
但是,當更多的需求來臨時,要求我們額外的整合一種或者多種社交登入,那該怎麼辦?難道我們還要任性的在表結構中添加相應的欄位?
Schema::table('users', function ($table) { $table->string('github_id'); $table->string('douban_id');});
這很明顯的違背了開放封閉原則,假如我們這麼做,那麼可以想象的當每多整合一種登入時,我們就需要對資料表結構做出一次修正,並且,在登入授權回調驗證時,還要增加一道整合驅動與欄位查詢匹配的工序。
那應該怎麼做?
設想
這麼想來,User 表是否承擔了過多的能力,它是否應該浪費自己的精力來管理這些社交標識?那不如我們安排 SocialiteUser 來專門系統管理使用者與社交帳號之間的關係?我們需要設計一種易擴充的方案來管理不同驅動的社交登入,那麼我們很容易的設計出這種表結構:
- socialite_users - id - user_id - driver - open_id
SocialiteUser 應該具有哪些職責?很顯然,它主要用來維護社交登入標識和使用者模型之間的關係。那麼它應該具有以下能力:
將社交登入賬戶綁定到使用者模型上
擷取匹配的使用者模型
以下為簡單的代碼示範:
where([ 'driver' => $driver, 'open_id' => $openid ])->first(); return $finder ? $finder->user : $finder; } /** * get related user model. * * @return /App/User||null */ public function user() { return $this->belongsTo('App\User'); } /** * Save a new record. * * @param $userId integer * @param $driver string * @param $id string * @return /App/SocialiteUser */ public function saveOne($userId, $driver, $id) { return $this->create([ 'user_id' => $userId, 'driver' => $driver, 'open_id' => $id ]); }}
使用
在授權登入流程中,使用者同意授權,第三方應用將重新導向到回調路由,回調路由中 Socialite 會主動請求擷取使用者資料,並將使用者的社交標識 ID 映射到 User 模型的 id 屬性上。
那麼我們就可以在回調路由中根據驅動標識和使用者相應的社交標識 ID 來匹配查詢庫中是否已存在綁定的使用者。如果存在那就直接使用匹配到的使用者登入,如果不存在,那麼就產生一個使用者,並為這個使用者附加社交賬戶資訊。然後使用新產生的賬戶登入。
redirect(); } public function handleProviderCallback($driver) { $user = Socialite::driver($driver)->user(); $model = new User(); $socialiteUser = new SocialiteUser(); $finder = $socialiteUser->getUser($driver, $user->id); if (! $finder) { $finder = $model->generateUserInstance(); $finder->save(); $socialiteUser->saveOne($finder->id, $driver, $user->id); } Auth::login($finder); return view('home'); }}
這樣看來,如果需求一種新的社交登入的整合,那麼完全不需要做出其它代碼的改動,直接配置驅動就可以了。
PS: 歡迎關注簡書 Laravel 專題,也歡迎 Laravel 相關文章的投稿 :),作者知識技能水平有限,如果你有更好的設計方案歡迎討論交流,如果有錯誤的地方也請批評指正,在此表示感謝謝謝 :)