首頁  >  文章  >  後端開發  >  淺談多個社群帳號的綁定設計

淺談多個社群帳號的綁定設計

WBOY
WBOY原創
2016-09-28 08:54:131110瀏覽

Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方帳號登入整合的問題,那麼在取得到使用者資料之後呢?整合多個社交帳號,該如何綁定同一個帳號?本篇就讓我們來探討一下整合登入的那點事。

起初,當我們只需要整合單一社交登入時,我們可能會為了快速的完成任務簡單粗暴的在用戶模型中加入open_id 或者github_id 類似的屬性,那麼在資料庫中,我們需要在表中添加相應的字段。這是可以快速有效的完成任務的做法。

但是,當更多的需求來臨時,要求我們額外的整合一種或多種社交登錄,那該怎麼辦?難道我們還要任性的在表格結構中加入對應的欄位?

<code class="php">Schema::table('users', function ($table) {
  $table->string('github_id');
  $table->string('douban_id');
});</code>

這很明顯的違背了開放封閉原則,假如我們這麼做,那麼可以想像的當每多集成一種登錄時,我們就需要對數據表結構做出一次修正,並且,在登錄授權回調驗證時,還要增加一道集成驅動與字段查詢匹配的工序。

那該怎麼做?

設想

這麼想來,User 表是否承擔了過多的能力,它是否應該浪費自己的精力來管理這些社交標誌?那不如我們安排 SocialiteUser 專門管理使用者與社群帳號之間的關係?我們需要設計一個易擴展的方案來管理不同驅動的社交登錄,那麼我們很容易的設計出這種表結構:

<code class="php">- socialite_users
  - id
  - user_id
  - driver
  - open_id</code>

SocialiteUser 應該具備哪些職責?很顯然,它主要用來維護社交登入標識和使用者模型之間的關係。那麼它應該要有以下能力:

  • 將社群登入帳號綁定到使用者模型上

  • 取得符合的使用者模型

以下為簡單的程式碼示範:

<code class="php"><?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
       ]);
    }
}
</code>

使用

在授權登入流程中,使用者同意授權,第三方應用將重新導向到回呼路由,回呼路由中 Socialite 會主動請求獲取使用者資料,並將使用者的社交識別 ID 對應到 User 模型的 id 屬性上。

那麼我們就可以在回呼路由中根據驅動標識和用戶相應的社交標識 ID 來匹配查詢庫中是否已存在綁定的用戶。如果存在那就直接使用匹配到的用戶登錄,如果不存在,那麼就產生一個用戶,並為這個用戶附加社交帳戶資訊。然後使用新產生的帳戶登入。

<code class="php"><?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');
    }
}
</code>

這樣看來,如果需求一種新的社交登入的集成,那麼完全不需要做出其它代碼的改動,直接配置驅動就可以了。

PS: 歡迎關注簡書Laravel 專題,也歡迎Laravel 相關文章的投稿:),作者知識技能水平有限,如果你有更好的設計方案歡迎討論交流,如果有錯誤的地方也請批評指正,在此表示謝謝謝謝:)

回覆內容:

Dearmadman 在 Laravel Socialite 詳解 中使用 larastarscn/socialite 解決了第三方帳號登入整合的問題,那麼在取得到使用者資料之後呢?整合多個社交帳號,該如何綁定同一個帳號?本篇就讓我們來探討一下整合登入的那點事。

起初,當我們只需要整合單一社交登入時,我們可能會為了快速的完成任務簡單粗暴的在用戶模型中加入open_id 或者github_id 類似的屬性,那麼在資料庫中,我們需要在表中添加相應的字段。這是可以快速有效的完成任務的做法。

但是,當更多的需求來臨時,要求我們額外的整合一種或多種社交登錄,那該怎麼辦?難道我們還要任性的在表格結構中加入對應的欄位?

<code class="php">Schema::table('users', function ($table) {
  $table->string('github_id');
  $table->string('douban_id');
});</code>

這很明顯的違背了開放封閉原則,假如我們這麼做,那麼可以想像的當每多集成一種登錄時,我們就需要對數據表結構做出一次修正,並且,在登錄授權回調驗證時,還要增加一道集成驅動與字段查詢匹配的工序。

那該怎麼做?

設想

這麼想來,User 表是否承擔了過多的能力,它是否應該浪費自己的精力來管理這些社交標誌?那不如我們安排 SocialiteUser 專門管理使用者與社群帳號之間的關係?我們需要設計一個易擴展的方案來管理不同驅動的社交登錄,那麼我們很容易的設計出這種表結構:

<code class="php">- socialite_users
  - id
  - user_id
  - driver
  - open_id</code>

SocialiteUser 應該具備哪些職責?很顯然,它主要用來維護社交登入標識和使用者模型之間的關係。那麼它應該要有以下能力:

  • 将社交登录账户绑定到用户模型上

  • 获取匹配的用户模型

以下为简单的代码演示:

<code class="php"><?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
       ]);
    }
}
</code>

使用

在授权登录流程中,用户同意授权,第三方应用将重定向到回调路由,回调路由中 Socialite 会主动请求获取用户资料,并将用户的社交标识 ID 映射到 User 模型的 id 属性上。

那么我们就可以在回调路由中根据驱动标识和用户相应的社交标识 ID 来匹配查询库中是否已存在绑定的用户。如果存在那就直接使用匹配到的用户登录,如果不存在,那么就生成一个用户,并为这个用户附加社交账户信息。然后使用新生成的账户登录。

<code class="php"><?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');
    }
}
</code>

这样看来,如果需求一种新的社交登录的集成,那么完全不需要做出其它代码的改动,直接配置驱动就可以了。

PS: 欢迎关注简书 Laravel 专题,也欢迎 Laravel 相关文章的投稿 :),作者知识技能水平有限,如果你有更好的设计方案欢迎讨论交流,如果有错误的地方也请批评指正,在此表示感谢谢谢 :)

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn