web analytics

Laravel5 : ทำ Facebook Login บน Laravel 5

cover-2

บทความนี้ผมจะพามาทำ ล็อคอินด้วยโซเชียลอย่าง facebook บน Laravel 5 กันครับ เรื่องเริ่มจากผมได้เขียน Benznest wallet แล้วก็อยากจะทำล็อคอินด้วย facebook (เห็นคนอื่นเค้ามีก็อยากจะมีบ้าง) ซึ่งบทความนี้จะเหมาะกับคนที่พอจะเข้าใจ Laravel 5 มาบ้างแล้ว เพราะไม่ได้ลงรายละเอียดพื้นฐานมาก โดยผมจะสรุปความรู้ที่ได้ทำลงในบทความนี้ครับ

เป้าหมายของผมก็คือ ผมมีแบบล็อคอินเดิมของ Laravel อยู่แล้ว สามารถสมัครสมาชิกปกติ แต่จะเพิ่มล็อคอินเฟสบุ๊คเข้ามา โดยผู้ใช้สามารถใช้งานได้ทั้งสองวิธี กล่าวคือ ถ้าสมัครสมาชิกปกติก็ไปเพิ่มเฟสบุ๊คทีหลังได้ หรือถ้ากดล็อคอินด้วยเฟสบุ๊คแล้วอีเมลตรงกับสมาชิกที่มีอยู่เดิม ก็จะเอาบัญชีเดิมเพิ่มเฟสบุ๊คเข้าไป แล้วค่อยมีหน้าจัดการบัญชีอีกทีหนึ่ง แต่ถ้าไม่มีข้อมูลก็จะสมัครสมาชิกให้อัตโนมัติโดยเอาข้อมูลจากเฟสบุ๊คนั่นแหละ เย้ มาลุยกัน

เริ่มต้น

ก่อนอื่นเลยต้องไปสร้าง App ของ facebook ก่อนครับ

https://developers.facebook.com/apps/

กด New app จากนั้นก็เลือก เว็บไซต์ จากนั้นก็ใส่ชื่อแอปครับ แล้วก้ใส่รายละเอียดตามขั้นตอน

1

 

 

พอใส่รายละเอียดครบแล้ว ให้เข้ามาที่ My app แล้วเลือกแอปของเราครับ มาตั้งค่าก่อนที่ Settings ตรงนี้สำคัญครับ ให้ใส่ App Domain ลงไป ถ้าจะเทสบน localhost ก็ทำได้เหมือนกัน แต่ต้องไปกำหนดก่อน ว่าแอปเป็นแอปแบบทดสอบ แต่ในกรณีนี้ผมจะให้โฮสจริงไปเลย

2-1

 

 

ดาวน์โหลดไลบรารี่ผ่าน Composer

ขั้นตอนต่อมา เราต้องไปโหลดไลบรารี่ การล็อคอินมาผนวกกับเว็บ laravel ของเราครับ โดยไปที่โปรเจค Laravel ของเราแล้ว เปิดไฟล์ composer.json ขึ้นมา จากนั้นก็ใส่ dependencies ลงไปในส่วนของ require

"require": {
"laravel/framework": "5.0.*",
"laravel/socialite": "~2.0"
},

 

เสร็จแล้วก็ ทำการ update project ซะโดยเปิด terminal cmd ขึ้นมา แล้วก็เข้ามาที่ path project พิมพ์ว่า

composer update

 

หรือเข้าไปที่โปรเจคผ่าน file explorer แล้วคลิกขวา เลือก Update composer พอเปิดขึ้นมาก็กด enter ทีนึง

3

 

 

จากนั้นก็รอโหลด (ต่อเน็ตด้วยนะ)

4

 

 

ใส่ไลบรารี่ลงใน Laravel

หลังจากที่เราโหลดไลบรารี่มาแล้ว ตัวไลบรารี่จะไปอยู่ในโฟลเดอร์ /vendor ครับ แต่โปรเจคจะยังไม่ได้ไลบรารี่นำมาใช้ ต้องนำเข้ามาในโปรเจคก่อน ผ่านตัว Provider วิธีการคือเข้าไปที่ไฟล์ config/app.php แล้วเพิ่มชื่อ Class ลงไปใน providers

 

Laravel\Socialite\SocialiteServiceProvider::class,

 

 

จะได้ประมาณนี้ครับ

5

 

 

ต่อมาเราก็ไปเพิ่มชื่อย่อเพื่อให้เราสามารถเรียกได้ง่ายขึ้นด้วย วิธีการก็คือ ไปที่ไฟล์ config/app.php ไฟล์เดิม แล้วเลื่อนลงมาด้านล่าง ให้เพิ่มบรรทัดด้านล่างลงไปใน aliases

'Socialize' => Laravel\Socialite\Facades\Socialite::class

 

6

 

เท่านี้ โปรเจคของเราก็จะโหลดตัวคลาสของไลบรารี่เข้าไปแล้ว ทำงานได้อย่างสบายใจ ต่อมาเราต้องไปเพิ่มรายละเอียด service ที่ facebook ต้องใช้ โดยเข้าไปที่ config/service.php

    'facebook' => [
        'client_id' => '1234',
        'client_secret' => '1234',
        'redirect' => 'http://www.benzneststudios.com/benznestwallet/auth/login/facebook/index',
    ],

ตรงนี้คือเราต้องกำหนด client_id และ client_secret โดยนำมาจาก app facebook ที่เราสร้างไว้ตอนแรกนั่นเอง ส่วน redirect คือ ลิงค์ที่เราต้องการให้วิ่งไป หากล็อคอินผ่านแล้ว

 

เขียนโปรแกรมเรียกใช้งาน

หลังจากที่เราเตรียมการจนพร้อมแล้วทั้ง facebook app , library ต่างๆ ตอนนี้เราต้องมาเขียนโค้ดเพื่อใช้งานกันแล้ว เริ่มจากเตรียม Controller และ Route ก่อน โดยเตรียมไว้ 2 route  อันแรกคือสำหรับส่ง redirect ไปยัง facebook อันที่สองคือไว้สำหรับรอรับ call back จาก facebook ส่วน Controller ผมสร้างอันใหม่ชื่อว่า SocialLoginController

วิธีการสร้างใช้ terminal ก็ได้พิมพ์ว่า

php artisan make:controller SocialLoginController

 

หรือจะ copy code ตัว Controller เก่า มาแปะ แก้ไขใน new file ก็ได้ แล้วแต่สะดวก (ผมชอบทำวิธีนี้) ส่วน Route สามารถกำหนดได้ตามสะดวกเลยครับ ผมกำหนด ‘auth/login/facebook’ เป็น route สำหรับส่ง redirect ไปหา facebook โดยให้ไปเรียก method ที่ชื่อ facebookAuthRedirect

ส่วน ‘auth/login/facebook/index’ ก็ไปเรียก facebookSuccess

ไฟล์ route.php

// for redirect to facebook auth.
Route::get('auth/login/facebook', 'SocialLoginController@facebookAuthRedirect');
// facebook call back after login success.
Route::get('auth/login/facebook/index', 'SocialLoginController@facebookSuccess');

 

ทีนี้ก็ไป implement ตัว method สำหรับ redirect ไปที่ facebook

ไฟล์ SocialLoginController.php

ก่อนอื่น import ตัว class เข้ามาเพิ่มก่อนที่ด้านบนของไฟล์

use Socialize;
public function facebookAuthRedirect() {
	return Socialize::with('facebook')->redirect();
	}
);

 

มา implement ที่ method facebookSuccess กันบ้าง

public function facebookSuccess() {

	$provider = Socialize::with('facebook');
	if (Input::has('code')){
		$user = $provider->stateless()->user();
		dd($user); // print value debug.
	}
}

ทำการรับค่าจาก callback จาก facebook ก่อน แล้วเช็คว่าที่ส่งมา มีส่งมาจริงๆนะ แล้วก็ดึงข้อมูลส่วน user ออกมา ผมจะลอง print debug ก่อน โดยใช้ dd()

 

ให้ลองเข้าไปที่ route ที่เรากำหนดไว้ (ล็อคอินเฟสบุ๊คไว้ด้วย)

auth/login/facebook

 

หากถูกต้องมันจะวิ่งไปที่ facebook แล้วส่งข้อมูลกลับมาแบบนี้

7

หากมี error ที่เฟสบุ๊คก็ต้องไปแก้ ที่ Facebook App ของเราครับ ส่วนใหญ่น่าจะเป็นที่ App domain ต้องตั้งให้ตรงกับเว็บของเรา

พอได้รับผลกลับมาแล้ว ที่เหลือเราก็ดึงค่าออกมาจากตัวแปร user ก็จะได้พวก email, name, facebook_id (อย่าลืมไปสร้างฟิล facebook_id ในฐานข้อมูลด้วยนะ ถ้าอยากจะเก็บ)

 $email = $user->email;
$name = $user->name;
$facebook_id = $user->id;

 

 

ทีนี้ต้องระวังนิดนึงด้วย เพราะผู้ใช้บางคน กำหนด privacy ไม่แสดง email ทำให้ค่าของ email อาจจะเป็น null ได้ เดี๋ยวใส่ลงไปในฐานข้อมูลจะพังได้ (ถ้าไปตั้งว่า email  ต้อง unique) ดังนั้นเราต้องมาจัดการตรงนี้ด้วย วิธีการก็แค่เช็คว่า email เป็น null หรือไม่

if($email == null){ // case permission is not email public.
	$user = $this->checkExistUserByFacebookId($facebook_id);
	if($user == null){
		$email = $facebook_id;
	}
}
else
{
	$user = $this->checkExistUserByEmail($email);
	if($user != null){
		if($user->facebook_id == ""){ // update account when not have facebook id.
			$user->facebook_id = $facebook_id;
			$user->save();
		}
	}
}

 

 

จากนั้นก็แล้วแต่จะจัดการครับ ขอยกตัวอย่างล็อคอินของผมที่ทำละกันครับ ถ้าระบบเราสามารถจะล็อคอินแบบปกติได้ด้วย ใช้อีเมล รหัสผ่าน (2 ช่องทาง) ก็ดูว่า facebook ส่งอีเมลผู้ใช้มาด้วยรึปล่าว ถ้ามีก็เอาอีเมลนี้แหละ แต่ถ้าไม่มี ก็อาจจะต้องหาอะไรมาใส่แทนอีเมลครับ เพราะไม่ควรว่างฟิลอีเมลไว้ในฐานข้อมูล ผมเลยใช้ facebook_id ใส่แทนอีเมลลงไป (ไม่มีซ้ำกัน) และอย่าลืมว่าผู้ใช้ที่กดเข้ามา อาจจะเป็นทั้งคนเก่า (สมาชิกเดิม) และคนใหม่ ดังนั้นต้องเอา facebook_id หรือ อีเมลไปหาในฐานข้อมูลก่อนว่าเคยมีคนนี้มัย ถ้ามีก็คือคนเก่าเราก็ล็อคอินเข้าไป แต่ถ้าไม่มีก็ทำการสมัครสมาชิกอัตโนมัติ

ฟังก์ชันสำหรับเช็คว่าเป็นสมาชิกเดิมหรือปล่าว ทำได้หลายวิธีครับ แต่ผมใช้ Eloquent ที่ผูกกับ Model ละกัน หากมีข้อมูลผู้ใช้อยู่แล้วมันก็จะ return object ของ user คนนั้นออกมาให้ แต่ถ้าไม่มีก็จะเป็น null

private function checkExistUserByEmail($email){
	$user = \App\User::where('email','=',$email)->first();
	return $user;
}

private function checkExistUserByFacebookId($facebook_id){
	$user = \App\User::where('facebook_id','=',$facebook_id)->first();
	return $user;
}

 

 

พอได้ object ของ user มาก็ง่ายแล้วครับ มาเช็คดูว่า เป็น null หรือไม่ ถ้าไม่เป็นก็เรียกใช้ login ได้เลยโดยการโยน Model ให้มันไป แล้วจะ authen ให้

Auth::login($user);

 

หรือจะล็อคอินด้วย primary key ก็ได้ โดยเรียก loginUsingId($id)

Auth::loginUsingId($user_id);

 

แต่ถ้ากรณีเป็น null ก็สมัครสมาชิกก่อน โดยไปสร้าง User ใหม่ แล้วค่อยล็อคอิน หรือจะทำอะไรก็แล้วแต่ต้องการ ถ้าทุกอย่างเสร็จแล้วผมจะให้ redirect ไปหน้าแรก

if($user != null){ // Auth exist account.
	Auth::login($user);
	return redirect('index/');
}
else{ // new Account.
	$user = $this->registerUser($email,$name,$password,$facebook_id);
	Auth::login($user);
	return redirect('index/');
}

 

 

ทำการเขียนฟังก์ชัน สมัครสมาชิก โดยผมทำผ่าน Model เลย ส่วนรหัสผ่านผู้ใช้ แน่นอนว่าก็ไม่ควรว่างไว้ แต่จะใส่อะไรดีละ จะ fix ไว้ก็คงไม่ดี แล้วผู้ใช้ก็ไม่จำเป็นต้องมากรอกรหัสผ่านด้วย ผมเลยใช้วิธีนำ token มาใส่แทนรหัสผ่านซะเลย (อาจจะตัดเอา 10 หรือ 20 ตัว) แล้วใส่ Hash

	private function registerUser($email,$name,$password,$facebook_id){
 		$user = new \App\User;
		$user->email = $email;
		$user->name = $name;
		$user->password = Hash::make($password); // Hash::make
		$user->balance = 0;
		$user->level = "member";
		$user->facebook_id = $facebook_id;
		$user->save();

		return $user;
 	}

 

 

สรุป SocialLoginController.php

<?php namespace App\Http\Controllers;
use Input;
use Socialize;
use Auth;
use Redirect;
use Hash;

class SocialLoginController extends Controller {
	public function __construct()
	{
	}

	public function index()
	{
		return view('home');
	}

	public function facebookAuthRedirect() {
 	 	return Socialize::with('facebook')->redirect();
 	}

 	public function facebookSuccess() {

 	  	$provider = Socialize::with('facebook');
 	  	if (Input::has('code')){
	    	$user = $provider->stateless()->user();
	    	//dd($user);
	    	$email = $user->email;
	    	$name  = $user->name;
	    	$password = substr($user->token,0,10);
	    	$facebook_id = $user->id;

	    	if($email == null){ // case permission is not email public.
	    		$user = $this->checkExistUserByFacebookId($facebook_id); 
	    		if($user == null){
	    			$email = $facebook_id;
	    		}
	    	}
	    	else
	    	{
	    		$user = $this->checkExistUserByEmail($email); 
	    		if($user != null){
		    		if($user->facebook_id == ""){ // update account when not have facebook id.
		    			$user->facebook_id = $facebook_id;
		    			$user->save();
		    		}
	    		}
	    	}

		    if($user != null){ // Auth exist account.
		    	Auth::login($user);
		    	return redirect('index/');
		    }
		    else{ // new Account.
		    	$user = $this->registerUser($email,$name,$password,$facebook_id);
		    	Auth::login($user);
		    	return redirect('index/');
		    }
		}
		return redirect('/');
 	}

 	private function checkExistUserByEmail($email){
 		$user = \App\User::where('email','=',$email)->first();
 		return $user;
 	}

 	private function checkExistUserByFacebookId($facebook_id){
 		$user = \App\User::where('facebook_id','=',$facebook_id)->first();
 		return $user;
 	}

 	private function registerUser($email,$name,$password,$facebook_id){
 		$user = new \App\User;

		$user->email = $email;
		$user->name = $name;
		$user->password = Hash::make($password); // Hash::make
		$user->facebook_id = $facebook_id;
		$user->save();

		return $user;
 	}
 
}

 

มาลองใช้งานกัน

วิธีใช้งานนั้นง่ายมาก ไปที่ View แล้วก็ทำปุ่มมาสักปุ่มนึง จากนั้นแปะลิงค์ให้มันไป แล้วก็เรียกใช้งาน route ที่ชื่อว่า /auth/login/facebook เป็นอันเสร็จพิธี

<a href="{{ url('auth/login/facebook') }}"><img src="{{ url('img/btn_facebook.png')}}" width="200px"> </a>

 

8

 

 

ส่วนกรณีที่ ผู้ใช้สมัครสมาชิกเข้ามาแต่ไม่ได้ให้ email  มาด้วย (email เป็น null) จากโค้ดที่เราเขียนจะทำให้ email เป็น facebook_id ใช่มัยครับ แถมรหัสยังเป็น token อีก ดังนั้นผู้ใช้จะยังล็อคอินตรงๆไม่ได้ ดังนั้นอาจจะต้องทำหน้าตั้ง email รหัสผ่านให้เขาด้วยนั่นเอง อันนี้แล้วแต่สะดวกเลยครับ หรือจะเลือกไม่ให้สมัครสมาชิกตั้งแต่แรกเลยก็ได้ ตัดปัญหา ให้ reject ออกไปเลย (ไปเอาอีเมลมาก่อนสิ) อีกวิธีคือก็ให้เขาล็อคอินแค่เฟสบุ๊คนี่แหละ ไม่ต้องไปใช้ล็อคอินของเรา

9

สรุป

การทำล็อคอินเฟสบุ๊ค บน Laravel 5 นั้น ขั้นตอนหลัๆกคือ implement ส่วน controller ที่เหลือแค่สมัคร Facebook App โหลดไลบรารี่ เพิ่ม provider และ service นิดหน่อย  ซึ่งระบบสมาชิก ในแต่ละที่นั้นต่างกัน อยู่ที่ระบบจัดการ บางที่ไม่ต้องการให้ล็อคอินได้หลายวิธี บางที่สามารถล็อคอินได้โดยตรงด้วย ตรงนี้ก็สามารถจัดการได้หลายแบบครับ โค้ดที่ผมเขียนเป็นตัวอย่างเท่านั้นครับ สามารถลองนำไปปรับใช้ ประยุกต์ให้เข้ากับระบบได้ครับ หวังว่าบทความนี้จะเป็นประโยชน์กับผู้ที่สนใจไม่มากก็น้อยครับ

ขอบคุณที่ติดตามครับ (: