12/08/2018, 15:14

Laravel social login

Ở thời điểm viết bài mình sử dụng phiên bản Laravel 5.4 để thực hiện chức năng Social login cụ thể là Laravel 5.4 facebook login, các tài khoảng twitter, google, github,.. các bạn làm tương tự, mình sẽ nói ngắn gọi ở trong bài. 1. Vấn đề Input : Thực hiện chức năng đăng nhập bằng email ...

  • Ở thời điểm viết bài mình sử dụng phiên bản Laravel 5.4 để thực hiện chức năng Social login cụ thể là Laravel 5.4 facebook login, các tài khoảng twitter, google, github,.. các bạn làm tương tự, mình sẽ nói ngắn gọi ở trong bài.

1. Vấn đề

Input:

  • Thực hiện chức năng đăng nhập bằng email (cái này Laravel đã hỗ trợ sẵn nên mình bỏ qua) và cho phép đăng nhập bằng facebook.

Output:

  • Tạo được tài khoản đăng nhập vào ứng dụng Laravel với tài khoản facebook.

2. Giải pháp

  • Database:
    • Bảng users với các trường name, email,..
    • Bảng social_accounts với các trường user_id, provider_user_id, provider,...
  • Ý tưởng: Ta sẽ tạo ra link cho phép người dùng click vào để login bằng tài khoản facebook, khi người dùng click vào nút này ta sẽ get thông tin của người dùng từ tài khoản facebook và insert vào database rồi thực hiện login. Ở đây laravel đã cung cấp sẵn cho ta package Socialite để giải quyết vẫn đề này.
  • Thực hiện:
    • Cài đặt package socialite bằng composer

      composer require laravel/socialite
      
    • Thêm providers vào file config/app.php

      'providers' => [
         // Other service providers...
      
         LaravelSocialiteSocialiteServiceProvider::class,
      ],
      
    • Thêm alias

      'Socialite' => LaravelSocialiteFacadesSocialite::class,
      
    • Tiếp theo ta cần có một app facebook, bạn vào link này để tạo một app: https://developers.facebook.com/

    • Ta chọn Add a new app để tạo một app mới cho ứng dụng của ta, mình đã tạo sẵn app laravel54 với config như sau:

    • Ta lưu App ID, App Secret để tý thêm vào file config của ứng dụng và ta phải nhớ pubblic app này nhé:

    • OK phần app facebook, ta sẽ quay lại với ứng dụng laravel.

    • Đầu tiên ta cần thêm vào file config/services.php

      'facebook' => [
          'client_id' => env('FACEBOOK_APP_ID'),
          'client_secret' => env('FACEBOOK_APP_SECRET'),
          'redirect' => env('FACEBOOK_APP_CALLBACK_URL'),
      ],
      'github' => [
          'client_id' => env('GITHUB_APP_ID'),
          'client_secret' => env('GITHUB_APP_SECRET'),
          'redirect' => env('GITHUB_APP_CALLBACK_URL'),
      ],
      'twitter' => [
          'client_id' => env('TWITTER_APP_ID'),
          'client_secret' => env('TWITTER_APP_SECRET'),
          'redirect' => env('TWITTER_APP_CALLBACK_URL'),
      ],
      'google' => [
          'client_id' => env('GOOGLE_APP_ID'),
          'client_secret' => env('GOOGLE_APP_SECRET'),
          'redirect' => env('GOOGLE_APP_CALLBACK_URL'),
      ],
      
    • Nếu chỉ cần login bằng facebook thì ta chỉ cần thêm config services cho tài khoản facebook thôi, ở đây mình muốn nói đối với các tài khoản khác cũng tương tự. Các config này ta sẽ thêm sau vào file .env.

    • Tiếp theo ta tạo controller SocialAuthController

      php artisan make:controller SocialAuthController
      
    • Thêm 2 method redirect và callback

      namespace AppHttpControllers;
      
      use IlluminateHttpRequest;
      
      use AppHttpRequests;
      use AppServicesSocialAccountService;
      use IlluminateSupportFacadesLog;
      use Socialite;
      
      class SocialAuthController extends Controller
      {
          public function redirect($social)
          {
              return Socialite::driver($social)->redirect();
          }
      
          public function callback($social)
          {
              $user = SocialAccountService::createOrGetUser(Socialite::driver($social)->user(), $social);
              auth()->login($user);
      
              return redirect()->to('/home');
          }
      }
      
    • Service SocialAccountService để xử lý tạo mới user hoặc get user từ database, file này mình để trong thư mục appServices:

      namespace AppServices;
      
      use LaravelSocialiteContractsUser as ProviderUser;
      use AppSocialAccount;
      use AppUser;
      
      class SocialAccountService
      {
          public static function createOrGetUser(ProviderUser $providerUser, $social)
          {
              $account = SocialAccount::whereProvider($social)
                  ->whereProviderUserId($providerUser->getId())
                  ->first();
      
              if ($account) {
                  return $account->user;
              } else {
                  $email = $providerUser->getEmail() ?? $providerUser->getNickname();
                  $account = new SocialAccount([
                      'provider_user_id' => $providerUser->getId(),
                      'provider' => $social
                  ]);
                  $user = User::whereEmail($email)->first();
      
                  if (!$user) {
      
                      $user = User::create([
                          'email' => $email,
                          'name' => $providerUser->getName(),
                          'password' => $providerUser->getName(),
                      ]);
                  }
      
                  $account->user()->associate($user);
                  $account->save();
      
                  return $user;
              }
          }
      }
      
    • Đoạn getEmail() mình check nếu không get được thì sẽ set email bằng nickName do tài khoản twitter mà để private email thì ta sẽ không get được email, trường hợp này bạn có thể bắt người dùng update email rồi mới cho login cũng rất đơn giản. Hoặc ta sẽ set thêm cho bảng user trường email có thể null như sau:

      $table->string('email')->unique()->nullable();
      
    • Tất nhiên là ta phải nhớ thêm bảng social_accounts và model cho nó:

      php artisan make:migration create_social_accounts_table --create="social_accounts"
      php artisan make:model SocialAccount
      
    • Thêm vào file migrate

      Schema::create('social_accounts', function (Blueprint $table) {
          $table->integer('user_id');
          $table->string('provider_user_id');
          $table->string('provider');
          $table->timestamps();
      });
      
    • Thêm quan hệ và model SocialAccount

      namespace App;
      
      use IlluminateDatabaseEloquentModel;
      
      class SocialAccount extends Model
      {
          protected $fillable = ['user_id', 'provider_user_id', 'provider'];
      
          public function user()
          {
              return $this->belongsTo('AppUser');
          }
      }
      
    • Thêm vào routes/web.php

      Route::get('/redirect/{social}', 'SocialAuthController@redirect');
      Route::get('/callback/{social}', 'SocialAuthController@callback');
      
    • Method redirect sẽ điều hướng người dùng đến facebook để xác nhận và method callback để xử lý gọi lại từ facebook.

    • Đến đây ta sẽ update file .env như sau:

      FACEBOOK_APP_ID = 642423652634577
      FACEBOOK_APP_SECRET = 91ffb713415e5e11f2a9f464a48c83b3
      FACEBOOK_APP_CALLBACK_URL = http://localhost:8000/callback/facebook
      
    • Twitter, google, github ta cũng làm tương tự, nếu bạn muốn test thử thì có thể dùng luôn key của app mình đã tạo sẵn:

      GITHUB_APP_ID = 79f02d69b8205fe2282b
      GITHUB_APP_SECRET = c82b3d193f3bf22b590d13ce47bd1e9da148026c
      GITHUB_APP_CALLBACK_URL = http://localhost:8000/callback/github
      
      TWITTER_APP_ID = 9C83R9zQ2TOIEFW5k9hUbKks2
      TWITTER_APP_SECRET = DS5Si26a486MaqmBERsIcwJrjxVSYETm10KCeUhz5Tog6xBuyQ
      TWITTER_APP_CALLBACK_URL = http://localhost:8000/callback/twitter
      
      GOOGLE_APP_ID = 762749737436-vjblilaa7ijs906c3c9f5vgj7v3t78ks.apps.googleusercontent.com
      GOOGLE_APP_SECRET = 5drmbvkdCIXqOelFlMHaiExi
      GOOGLE_APP_CALLBACK_URL = http://localhost:8000/callback/google
      
    • Cuối cùng ta chỉ cần thêm link cho nút login bằng facebook và trải nghiệm thôi, chẳng hạn thêm <a href="redirect/facebook">FB Login</a> vào trang welcome.blade.php như mình chẳng hạn.

0