Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方賬號登錄集成的問題,那么在獲取到用戶資料之后呢?集成多個社交賬號,該如何綁定同一個賬號?本篇就讓我們來探討一下集成登錄的那點事。
起初
起初,當我們只需要集成單個社交登錄時,我們可能會為了快速的完成任務簡單粗暴的在用戶模型中加入 open_id 或者 github_id 類似的屬性,那么在數(shù)據(jù)庫中,我們需要在表中添加相應的字段。這是可以快速有效的完成任務的做法。
但是,當更多的需求來臨時,要求我們額外的集成一種或者多種社交登錄,那該怎么辦?難道我們還要任性的在表結(jié)構(gòu)中添加相應的字段?
Schema::table('users', function ($table) {
$table->string('github_id');
$table->string('douban_id');
});
這很明顯的違背了開放封閉原則,假如我們這么做,那么可以想象的當每多集成一種登錄時,我們就需要對數(shù)據(jù)表結(jié)構(gòu)做出一次修正,并且,在登錄授權(quán)回調(diào)驗證時,還要增加一道集成驅(qū)動與字段查詢匹配的工序。
那應該怎么做?
設想
這么想來,User 表是否承擔了過多的能力,它是否應該浪費自己的精力來管理這些社交標識?那不如我們安排 SocialiteUser 來專門管理用戶與社交賬號之間的關(guān)系?我們需要設計一種易擴展的方案來管理不同驅(qū)動的社交登錄,那么我們很容易的設計出這種表結(jié)構(gòu):
- socialite_users
- id
- user_id
- driver
- open_id
SocialiteUser 應該具有哪些職責?很顯然,它主要用來維護社交登錄標識和用戶模型之間的關(guān)系。那么它應該具有以下能力:
- 將社交登錄賬戶綁定到用戶模型上
- 獲取匹配的用戶模型
以下為簡單的代碼演示:
<?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
]);
}
}
使用
在授權(quán)登錄流程中,用戶同意授權(quán),第三方應用將重定向到回調(diào)路由,回調(diào)路由中 Socialite 會主動請求獲取用戶資料,并將用戶的社交標識 ID 映射到 User 模型的 id 屬性上。
那么我們就可以在回調(diào)路由中根據(jù)驅(qū)動標識和用戶相應的社交標識 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');
}
}
這樣看來,如果需求一種新的社交登錄的集成,那么完全不需要做出其它代碼的改動,直接配置驅(qū)動就可以了。
PS: 歡迎關(guān)注簡書 Laravel 專題,也歡迎 Laravel 相關(guān)文章的投稿 :),作者知識技能水平有限,如果你有更好的設計方案歡迎討論交流,如果有錯誤的地方也請批評指正,在此表示感謝謝謝 :)