Laravel Socialite tích hợp xác thực Twitter vào website

Tiếp theo series tích hợp xác thực bằng mạng xã hội vào website thông qua gói Laravel Socialite, chúng ta đã lần lượt tìm hiểu tích hợp xác thực Facebook, Google. Bài viết này sẽ tìm hiểu cách tích hợp xác thực Twitter vào website. Twitter cũng là một mạng xã hội được dân công nghệ dùng khá nhiều do vậy bên cạnh hai ông lớn Facebook và Google, bạn cũng nên tích hợp xác thực Twitter vào website của bạn. Các bài viết về tích hợp xác thực sẽ sử dụng 5 bước.

5 bước tích hợp xác thực Twitter vào website bằng Laravel Socialite

Bước 1: Cài đặt và thiết lập Laravel Socialite (tùy chọn, bỏ qua nếu bạn đã cài đặt)

Chúng ta sử dụng gói Laravel Socialite cho việc tích hợp, cài đặt gói này bằng lệnh composer như sau:

c:\xampp\htdocs\laravel-test>composer require laravel/socialite
Using version ^3.0 for laravel/socialite
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 2 installs, 0 updates, 0 removals
  - Installing league/oauth1-client (1.7.0): Loading from cache
  - Installing laravel/socialite (v3.0.5): Loading from cache
Writing lock file
Generating autoload files
> Illuminate\Foundation\ComposerScripts::postUpdate
> php artisan optimize
Generating optimized class loader
The compiled services file has been removed.

Tiếp theo cấu hình Laravel Socialite trong config/app.php:

...
'providers' => [
    ...
    Laravel\Socialite\SocialiteServiceProvider::class,
],
'aliases' => [
    ...
    'Socialite' => Laravel\Socialite\Facades\Socialite::class,
],

Bước 2: Thiết lập cấu hình Twitter

Cũng giống như tích hợp Facebook và Google, chúng ta cần tạo một ứng dụng mới trong Twitter Application. Bạn vào trang Twitter Application và đăng nhập bằng tài khoản Twitter, khi đó bạn sẽ thấy màn hình chính của Twitter Application, click vào Create New App.

Tạo ứng dụng mới trong Twitter Application

Tiếp theo, bạn thực hiện điền các thông tin cần thiết để tạo ứng dụng mới trong Twitter Application.

Thông tin tạo ứng dụng mới trong Twitter Application

Click vào Create your Twitter application, ứng dụng mới đã được tạo, trong cửa sổ tiếp theo bạn có thể thiết lập các thông tin như:

  • Tên công ty.
  • Logo công ty.
  • Đường dẫn Privacy Policy và Terms of Service.

Quan trọng nhất là trong tab Keys and Access Tokens bạn sẽ có được API key và API secret để thiết lập cho config/service.php.

API key vaf api secret dùng cho thiết lập Laravel Socialite

Ok, như vậy chúng ta đã thiết lập trong các cấu hình trên Twitter Application, tiếp theo là các công việc xử lý viết code.

Bước 3: Thay đổi bảng users (Tùy chọn, nếu bạn đã thực hiện ở bài tích hợp xác thực Facebook, Google có thể bỏ qua)

Trong ứng dụng Laravel, khi cần xác thực người dùng dùng câu lệnh artisan make:auth để tạo ra các view, route, controller cần thiết (Xem thêm Xác thực người dùng bằng Laravel Authenticaion). Khi đó, bảng users cũng được tạo ra, để lưu thêm các thông tin liên quan đến các mạng xã hội, chúng ta cần thêm các cột provider chứa tên mạng xã hội và provider_id là id của tài khoản mạng xã hội.

Chúng ta sẽ sử dụng Laravel Migration để thay đổi database (nên sử dụng vì trong các dự án lớn làm việc nhiều người, sử dụng Laravel Migration giúp quản lý được các phiên bản cấu trúc cơ sở dữ liệu).

c:\xampp\htdocs\laravel-test>php artisan make:migration alter2_users_table --tab
le=users
Created Migration: 2017_04_23_152423_alter2_users_table

alter2 do trong bài Xác thực tài khoản mới đăng ký qua email trong Laravel đã có file alter_users_table. Mở file 2017_04_23_152423_alter2_users_table trong thư mục database/migrations và thêm các đoạn mã tạo hai cột cần thiết:

<?php

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

class Alter2UsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('provider');
            $table->string('provider_id');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('provider');
            $table->dropColumn('provider_id');
        });
    }
}

Tiếp theo thực hiện lệnh php artisan migrate để thực hiện các thay đổi.

c:\xampp\htdocs\laravel-test>php artisan migrate
Migrated: 2017_04_23_152423_alter2_users_table

Bước 4: Thiết lập cấu hình dịch vụ cho Laravel Socialite trong config/service.php

Thiết lập các thông số trong config/service.php với các thông số API key và API secret có được ở bước 2 (các thông tin này đã được bôi mờ, bạn nên thiết lập tài khoản Twitter riêng):

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Third Party Services
    |--------------------------------------------------------------------------
    |
    | This file is for storing the credentials for third party services such
    | as Stripe, Mailgun, SparkPost and others. This file provides a sane
    | default location for this type of information, allowing packages
    | to have a conventional place to find your various credentials.
    |
    */

    'mailgun' => [
        'domain' => env('MAILGUN_DOMAIN'),
        'secret' => env('MAILGUN_SECRET'),
    ],

    'ses' => [
        'key' => env('SES_KEY'),
        'secret' => env('SES_SECRET'),
        'region' => 'us-east-1',
    ],

    'sparkpost' => [
        'secret' => env('SPARKPOST_SECRET'),
    ],

    'stripe' => [
        'model' => App\User::class,
        'key' => env('STRIPE_KEY'),
        'secret' => env('STRIPE_SECRET'),
    ],
    'google' => [
        'client_id' => '61159249             go4hovqiohip4h                       content.com',
        'client_secret' => '6xYdUYaf          pqcBpX',
        'redirect' => 'http://laravel.dev/auth/google/callback',
    ],
    'twitter' => [
        'client_id' => 'asTA0               3wBT',
        'client_secret' => 'hn1x              EWqMVI              JSvmE',
        'redirect' => 'http://laravel.dev/auth/twitter/callback',
    ],
];

Bước 5: Viết code cho route, view và SocialAuthController (nếu bạn đã thực hiện trong tích hợp Facebook, Google thì chỉ thay đổi mỗi view)

Thêm các route sau vào routes/web.php:

Route::get('/auth/{provider}', 'SocialAuthController@redirectToProvider');
Route::get('/auth/{provide}/callback', 'SocialAuthController@handleProviderCallback');

Do chúng ta tích hợp xác thực các mạng xã hội như Facebook, Google, Twitter nên chúng ta để tham số trong đường dẫn là provider có thể là facebook, google, twitter. Tạo SocialAuthController để xử lý việc xác thực, ghi nhận vào database… bằng lệnh artisan make:controller

c:\xampp\htdocs\laravel-test>php artisan make:controller SocialAuthController
Controller created successfully.

Tiếp đó, thêm code xử lý vào SocialAuthController.php vừa tạo (trong thư mục app\Http\Controllers\SocialAuthController.php):

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite, Auth, Redirect, Session, URL;
use App\User;

class SocialAuthController extends Controller
{
    /**
     * Chuyển hướng người dùng sang OAuth Provider.
     *
     * @return Response
     */
    public function redirectToProvider($provider)
    {
        if(!Session::has('pre_url')){
            Session::put('pre_url', URL::previous());
        }else{
            if(URL::previous() != URL::to('login')) Session::put('pre_url', URL::previous());
        }
        return Socialite::driver($provider)->redirect();
    }  

    /**
     * Lấy thông tin từ Provider, kiểm tra nếu người dùng đã tồn tại trong CSDL
     * thì đăng nhập, ngược lại nếu chưa thì tạo người dùng mới trong SCDL.
     *
     * @return Response
     */
    public function handleProviderCallback($provider)
    {
        $user = Socialite::driver($provider)->user();

        $authUser = $this->findOrCreateUser($user, $provider);
        Auth::login($authUser, true);
        return Redirect::to(Session::get('pre_url'));
    }

    /**
     * @param  $user Socialite user object
     * @param $provider Social auth provider
     * @return  User
     */
    public function findOrCreateUser($user, $provider)
    {
        $authUser = User::where('provider_id', $user->id)->first();
        if ($authUser) {
            return $authUser;
        }
        return User::create([
            'name'     => $user->name,
            'email'    => $user->email,
            'provider' => $provider,
            'provider_id' => $user->id
        ]);
    }
}

Nếu bạn đã thực hiện việc tích hợp xác thực bằng Facebook, Google thì các công đoạn trên có thể bỏ qua do bạn đã làm. Tiếp theo điều chỉnh view login.blade.php và register.blade.php để có phần Đăng nhập bằng Twitter và Đăng ký bằng Twitter.

Điều chỉnh nội dung resources/views/login.blade.php:

@extends('layouts.default')

@section('title', 'Đăng nhập - Allaravel.com')
@section('link-header')
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
@endsection
@section('content')
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Đăng nhập</div>
                <div class="panel-body">
                    @if (session('warning'))
                        <span class="alert alert-warning help-block">
                            <strong>{{ session('warning') }}</strong>
                        </span>
                    @endif                    

                    <form class="form-horizontal" role="form" method="POST" action="{{ route('login') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">Địa chỉ email</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required autofocus>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <div class="checkbox">
                                    <label>
                                        <input type="checkbox" name="remember" {{ old('remember') ? 'checked' : '' }}> Ghi nhớ mật khẩu
                                    </label>
                                </div>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-8 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Đăng nhập
                                </button>

                                <a class="btn btn-link" href="{{ route('password.request') }}">
                                    Quên mật khẩu?
                                </a>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-8">
                                <a class="btn btn-link" href="{{ URL::to('auth/facebook') }}">
                                    <i class="fa fa-facebook-official" aria-hidden="true"></i> Đăng nhập bằng Facebook
                                </a>
                                <a class="btn btn-link" href="{{ URL::to('auth/google') }}">
                                    <i class="fa fa-google-plus-square" aria-hidden="true"></i> Đăng nhập bằng Google
                                </a>
                                <a class="btn btn-link" href="{{ URL::to('auth/twitter') }}">
                                    <i class="fa fa-twitter-square" aria-hidden="true"></i> Đăng nhập bằng Twitter
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
@endsection

Điều chỉnh nội dung resources/views/register.blade.php:

@extends('layouts.default')

@section('title', 'Đăng ký - Allaravel.com')
@section('link-header')
    <script src='https://www.google.com/recaptcha/api.js'></script>
    <link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
@endsection
@section('content')
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <div class="panel panel-default">
                <div class="panel-heading">Đăng ký thành viên</div>
                <div class="panel-body">
                    <form class="form-horizontal" role="form" method="POST" action="{{ route('register') }}">
                        {{ csrf_field() }}

                        <div class="form-group{{ $errors->has('name') ? ' has-error' : '' }}">
                            <label for="name" class="col-md-4 control-label">Họ và tên</label>

                            <div class="col-md-6">
                                <input id="name" type="text" class="form-control" name="name" value="{{ old('name') }}" required autofocus>

                                @if ($errors->has('name'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('name') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('email') ? ' has-error' : '' }}">
                            <label for="email" class="col-md-4 control-label">Địa chỉ email</label>

                            <div class="col-md-6">
                                <input id="email" type="email" class="form-control" name="email" value="{{ old('email') }}" required>

                                @if ($errors->has('email'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('email') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group{{ $errors->has('password') ? ' has-error' : '' }}">
                            <label for="password" class="col-md-4 control-label">Mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password" type="password" class="form-control" name="password" required>

                                @if ($errors->has('password'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('password') }}</strong>
                                    </span>
                                @endif
                            </div>
                        </div>

                        <div class="form-group">
                            <label for="password-confirm" class="col-md-4 control-label">Nhập lại mật khẩu</label>

                            <div class="col-md-6">
                                <input id="password-confirm" type="password" class="form-control" name="password_confirmation" required>
                            </div>
                        </div>

                        <div class="form-group">
                            <div class="col-md-offset-4 col-md-6">
                                <div class="g-recaptcha" data-sitekey="{{ env('GOOGLE_RECAPTCHA_KEY') }}" data-callback="YourOnSubmitFn"></div>
                                @if ($errors->has('g-recaptcha-response'))
                                    <span class="help-block">
                                        <strong>{{ $errors->first('g-recaptcha-response') }}</strong>
                                    </span>
                                @endif
                            </div>

                        </div>
    
                        <div class="form-group">
                            <div class="col-md-6 col-md-offset-4">
                                <button type="submit" class="btn btn-primary">
                                    Đăng ký
                                </button>
                            </div>
                        </div>
                        <div class="form-group">
                            <div class="col-md-6">
                                <a class="btn btn-link" href="{{ URL::to('auth/facebook') }}">
                                    <i class="fa fa-facebook-official" aria-hidden="true"></i> Đăng ký bằng Facebook
                                </a>
                                <a class="btn btn-link" href="{{ URL::to('auth/google') }}">
                                    <i class="fa fa-google-plus-square" aria-hidden="true"></i> Đăng ký bằng Google
                                </a>
                                <a class="btn btn-link" href="{{ URL::to('auth/twitter') }}">
                                    <i class="fa fa-twitter-square" aria-hidden="true"></i> Đăng ký bằng Twitter
                                </a>
                            </div>
                        </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>
@endsection

Kiểm tra kết quả tích hợp xác thực Twitter bằng Laravel Socialite

Ok, vậy là chúng ta đã chuẩn bị xong các bước cần thiết cho tích hợp Twitter vào website, chú ý nếu bạn đã thực hiện tích hợp Facebook hoặc Google vào website bằng Laravel Socialite bạn sẽ thấy rằng có thể bỏ qua được các bước 1,3 và 1 phần bước 5. Chúng ta kiểm tra kết quả đạt được xem thế nào, truy cập đường dẫn http://laravel.dev/login hoặc http://laravel.dev/register bạn sẽ thấy đã có đường link Đăng nhập bằng Twitter và Đăng ký bằng Twitter.

Màn hình đăng nhập có tích hợp Twitter

Màn hình đăng ký có tích hợp Twitter

Hai đường dẫn Đăng nhập bằng Twitter và Đăng ký bằng Twitter là một, do chúng ta đã xử lý trong phương thức findOrCreate() trong SocialAuthController, để hai text khác nhau để người dùng cảm nhận là ở trong trang đăng nhập sẽ đăng nhập với Twitter và trong trang đăng ký sẽ là Đăng ký bằng Twitter mà thôi.

Khi bạn click vào các đường dẫn này, trang đăng nhập của Twitter sẽ hiển thị ra.

Chuyển hướng đến trang đăng nhập Twitter

Khi đăng nhập vào, Twitter sẽ hỏi bạn có cho phép chia sẻ thông tin đăng nhập trên Twitter với website không?

Twitter hỏi bạn có cho phép chia sẻ thông tin không

Click vào Authorize app là bạn đã cho phép chia sẻ xác thực này với website laravel.dev, như vậy là bạn đã đăng nhập thành công vào laravel.dev thông qua Twitter.

Add Comment