Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方帳號登陸集成的問題,那麼在獲取到用戶資料以後呢?集成多個社交帳號,該如何綁定同一個帳號?本篇就讓咱們來探討一下集成登陸的那點事。php
起初,當咱們只須要集成單個社交登陸時,咱們可能會爲了快速的完成任務簡單粗暴的在用戶模型中加入 open_id 或者 github_id 相似的屬性,那麼在數據庫中,咱們須要在表中添加相應的字段。這是能夠快速有效的完成任務的作法。git
可是,當更多的需求來臨時,要求咱們額外的集成一種或者多種社交登陸,那該怎麼辦?難道咱們還要任性的在表結構中添加相應的字段?github
Schema::table('users', function ($table) { $table->string('github_id'); $table->string('douban_id'); });
這很明顯的違背了開放封閉原則,假如咱們這麼作,那麼能夠想象的當每多集成一種登陸時,咱們就須要對數據表結構作出一次修正,而且,在登陸受權回調驗證時,還要增長一道集成驅動與字段查詢匹配的工序。數據庫
那應該怎麼作?ide
這麼想來,User 表是否承擔了過多的能力,它是否應該浪費本身的精力來管理這些社交標識?那不如咱們安排 SocialiteUser 來專門管理用戶與社交帳號之間的關係?咱們須要設計一種易擴展的方案來管理不一樣驅動的社交登陸,那麼咱們很容易的設計出這種表結構:this
- socialite_users - id - user_id - driver - open_id
SocialiteUser 應該具備哪些職責?很顯然,它主要用來維護社交登陸標識和用戶模型之間的關係。那麼它應該具備如下能力:spa
將社交登陸帳戶綁定到用戶模型上設計
獲取匹配的用戶模型3d
如下爲簡單的代碼演示:code
<?php namespace App; use Illuminate\Database\Eloquent\Model; class SocialiteUser extends Model { public $guarded = ['id']; /** * Get user instance by driver and openid. * * @param $driver string * @param $openid string * @return /App/User|null */ public function getUser($driver, $openid) { $finder = $this->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 來匹配查詢庫中是否已存在綁定的用戶。若是存在那就直接使用匹配到的用戶登陸,若是不存在,那麼就生成一個用戶,併爲這個用戶附加社交帳戶信息。而後使用新生成的帳戶登陸。
<?php namespace App\Http\Controllers; use App\SocialiteUser; use App\User; use Socialite; class OAuthAuthorizationController extends Controller { // public function redirectToProvider($driver) { return Socialite::driver($driver)->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 相關文章的投稿 :),做者知識技能水平有限,若是你有更好的設計方案歡迎討論交流,若是有錯誤的地方也請批評指正,在此表示感謝謝謝 :)