做完獨立的 Google+、 Facebook 與 Google 第三方登入,基本上大同小異,這次試著將它們全部整合在一起,讓使用者有更多的選擇來快速註冊與登入。
安裝 Laravel 6.x LTS 及 Authentication
參考官方網站步驟建立
composer create-project --prefer-dist laravel/laravel githubAuth "6.*"
composer require laravel/ui "^1.0" --dev
php artisan ui vue --auth
npm install && npm run dev
安裝 laravel/socialite
composer require laravel/socialite
修改 config/app.php
# providers 加入
Laravel\Socialite\SocialiteServiceProvider::class,
# aliases 加入
'Socialite' => Laravel\Socialite\Facades\Socialite::class,
修改 config/services.php,加入三個服務
'google' => [
'client_id' => env('GOOGLE_CLIENT_ID'),
'client_secret' => env('GOOGLE_CLIENT_SECRET'),
'redirect' => env('GOOGLE_REDIRECT'),
],
'facebook' => [
'client_id' => env('FACEBOOK_APP_ID'),
'client_secret' => env('FACEBOOK_APP_SECRET'),
'redirect' => env('FACEBOOK_REDIRECT'),
],
'github' => [
'client_id' => env('GITHUB_CLIENT_ID'),
'client_secret' => env('GITHUB_CLIENT_SECRET'),
'redirect' => env('GITHUB_REDIRECT'),
],
修改 route/web.php 新增
//訪客身分使用第三方登入路由,利用 {provider} 將所有的第三方登入共用同一個 redirect & callback function
Route::prefix('login')->group(function(){
Route::get('{provider}', 'Auth\SocialController@redirect');
Route::get('{provider}/callback', 'Auth\SocialController@callback');
});
建立 Auth\SocialController 控制器 (這次放在 Auth 目錄下)
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Socialite;
use App\Services\SocialAccountService;
use Session;
class SocialController extends Controller
{
/**
* Create a redirect method to provider api.
* 利用 Session 來傳遞 provider 變數
*/
public function redirect($request)
{
Session::put('provider', $request);
return Socialite::driver($request)->redirect();
}
/**
* Return a callback method from provider api.
* 透過 Session 找出 provider 變數並提供給 Socialite Class 使用
* @return callback URL from provider
*/
public function callback(SocialAccountService $service)
{
$provider = Session::get('provider');
$user = $service->createOrGetUser(Socialite::driver($provider)->user());
auth()->login($user);
return redirect()->to('/home');
}
}
建立 Model 及 修改相關檔案
php artisan make:model SocialAccount -m
修改 app/SocialAccount.php
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class SocialAccount extends Model
{
protected $fillable = ['user_id', 'provider_user_id', 'provider'];
public function user()
{
return $this->belongsTo(User::class);
}
}
修改 create_social_accounts_table.php
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateSocialAccountsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('social_accounts', function (Blueprint $table) {
$table->integer('user_id');
$table->string('provider_user_id');
$table->string('provider');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('social_accounts');
}
}
修改完成後執行 php artisan migrate:refresh 將資料庫建立起來。
新增 app/Services 目錄及 SocialAccountService.php
<?php
namespace App\Services;
use App\SocialAccount;
use App\User;
use Laravel\Socialite\Contracts\User as ProviderUser;
use Session;
class SocialAccountService
{
public function createOrGetUser(ProviderUser $providerUser)
{
//這邊透過Session將provider變數取出;
$provider = Session::get('provider');
$account = SocialAccount::whereProvider($provider)
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => $provider
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
'password' => md5(rand(1,10000)),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
修改 login 視圖,新增三個按鈕
<div class="form-group row mt-3">
<div class="col-md-3 offset-md-3">
<a href="{{url('/login/google')}}" class="btn btn-danger">Google+</a>
</div>
<div class="col-md-3">
<a href="{{url('/login/facebook')}}" class="btn btn-primary">Facebook</a>
</div>
<div class="col-md-3">
<a href="{{url('/login/github')}}" class="btn btn-secondary">Github</a>
</div>
</div>
編輯 .env 到 三個 Provider 修改 callback 位置。
GOOGLE_CLIENT_ID = XXXXXXXXXXXXXX
GOOGLE_CLIENT_SECRET = XXXXXXXXXXXX
GOOGLE_REDIRECT = https://localhost/login/google/callback
FACEBOOK_APP_ID = XXXXXXXXXXXXXXX
FACEBOOK_APP_SECRET = XXXXXXXXXXXXXXXXX
FACEBOOK_REDIRECT = https://localhost/login/facebook/callback
GITHUB_CLIENT_ID = XXXXXXXXXXXXXX
GITHUB_CLIENT_SECRET = XXXXXXXXXXXXXXXX
GITHUB_REDIRECT = https://localhost/login/github/callback
測試
從資料庫中可以看到使用了三種登入方式,因為我使用相同的 email 所以 user_id 都是 1。
成品同步放在我的 GitHub 上.