Dearmadman uses larastarscn/socialite in Laravel Socialite Detailed Explanation to solve the problem of third-party account login integration. So what happens after obtaining the user information? How to integrate multiple social accounts? How to bind the same account? In this article, let us discuss the integrated login.
Initially, when we only need to integrate a single social login, we may simply add open_id or github_id similar attributes to the user model in order to complete the task quickly. Then in the database, we need to add the corresponding fields to the table . This is a quick and efficient way to get the job done.
But when more demands come, requiring us to additionally integrate one or more social logins, what should we do? Do we still have to add corresponding fields to the table structure willfully?
<code class="php">Schema::table('users', function ($table) { $table->string('github_id'); $table->string('douban_id'); });</code>
This obviously violates the principle of openness and closure. If we do this, then it is conceivable that every time we integrate another login, we will need to make a correction to the data table structure, and during the login authorization callback verification, It is also necessary to add a process of integrating driver and field query matching.
What should we do?
Thinking about it this way, does the User table assume too much capacity? Should it waste its energy managing these social identifiers? How about we arrange SocialiteUser to specifically manage the relationship between users and social accounts? We need to design an easily scalable solution to manage social logins of different drivers, so we can easily design this table structure:
<code class="php">- socialite_users - id - user_id - driver - open_id</code>
What responsibilities should SocialiteUser have? Obviously, it is mainly used to maintain the relationship between social login identifiers and user models. Then it should have the following capabilities:
Bind social login accounts to user models
Get matching user model
The following is a simple code demonstration:
<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>
In the authorization login process, the user agrees to authorize, and the third-party application will redirect to the callback route. In the callback route, Socialite will actively request to obtain user information and map the user's social identification ID to the id attribute of the User
model.
Then we can use the driver ID and the user's corresponding social ID ID in the callback route to match whether there is a bound user in the query library. If it exists, log in directly with the matched user. If it does not exist, generate a user and attach social account information to this user. Then log in using the newly generated account.
<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>
It seems that if you need a new social login integration, then there is no need to make other code changes, just configure the driver directly.
PS: Welcome to pay attention to the Jianshu Laravel topic, and also welcome submissions of Laravel-related articles:). The author's knowledge and skills are limited. If you have a better design plan, you are welcome to discuss and exchange it. If there are any mistakes, please criticize and correct them here. Say thank you thank you :)
Dearmadman uses larastarscn/socialite in Laravel Socialite Detailed Explanation to solve the problem of third-party account login integration. So what happens after obtaining the user information? How to integrate multiple social accounts? How to bind the same account? In this article, let us discuss the integrated login.
Initially, when we only need to integrate a single social login, we may simply add open_id or github_id similar attributes to the user model in order to complete the task quickly. Then in the database, we need to add the corresponding fields to the table . This is a quick and efficient way to get the job done.
But when more demands come, requiring us to additionally integrate one or more social logins, what should we do? Do we still have to add corresponding fields to the table structure willfully?
<code class="php">Schema::table('users', function ($table) { $table->string('github_id'); $table->string('douban_id'); });</code>
This obviously violates the principle of openness and closure. If we do this, then it is conceivable that every time we integrate another login, we will need to make a correction to the data table structure, and during the login authorization callback verification, It is also necessary to add a process of integrating driver and field query matching.
What should we do?
Thinking about it this way, does the User table assume too much capacity? Should it waste its energy managing these social identifiers? How about we arrange SocialiteUser to specifically manage the relationship between users and social accounts? We need to design an easily scalable solution to manage social logins of different drivers, so we can easily design this table structure:
<code class="php">- socialite_users - id - user_id - driver - open_id</code>
What responsibilities should SocialiteUser have? Obviously, it is mainly used to maintain the relationship between social login identifiers and user models. Then it should have the following capabilities:
将社交登录账户绑定到用户模型上
获取匹配的用户模型
以下为简单的代码演示:
<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 相关文章的投稿 :),作者知识技能水平有限,如果你有更好的设计方案欢迎讨论交流,如果有错误的地方也请批评指正,在此表示感谢谢谢 :)