Laravel結合Facebook登入
前一篇: Laravel第三方登入-Facebook登入(一)
Facebook登入控制器
在使用laravel/socialite套件做Facebook登入功能時,指定使用facebook當作這次的第三方認證驅動,並設定重新導向的網址,即可連結到取得Facebook授權的網址
app/Http/Controllers/UserAuthController.php
<?PHP
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use Socialite;
use App\Shop\Entity\User; //使用者 Eloquent ORM Model
class UserAuthController extends Controller
{
//Facebook登入
public function facebookSignInProcess()
{
$redirect_url = env('FB_REDIRECT');
return Socialite::driver('facebook')
->scopes(['user_friends'])
->redirectUrl($redirect_url)
->redirect();
}
}
?>
resources/views/layout/master.blade.php
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>@yield('title') - Shop Laravel</title>
<script src="http://cdn.bootcss.com/jquery/1.11.0/jquery.min.js" type="text/javascript"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/js/bootstrap.min.js"></script>
<link href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<link href=" https://netdna.bootstrapcdn.com/font-awesome/4.5.0/css/font-awesome.min.css " rel="stylesheet" type="text/css" />
<link href="/css/style.css" rel="stylesheet" type="text/css" />
</head>
<boby>
<header>
<ul class="nav">
<li><a href="/">回首頁</a></li>
@if(session()->has('user_id'))
<li><a href="/user/auth/sign-out">登出</a></li>
@else
<li><a href="/user/auth/sign-in">登入</a></li>
<li><a href="/user/auth/facebook-sign-in">Facebook登入</a></li>
<li><a href="/user/auth/sign-up">註冊</a></li>
@endif
</ul>
</header>
<div class="container">
@yield('content')
</div>
<footer>
<a href="#">聯絡我們</a>
</footer>
</body>
</html>
在連結到 /user/auth/facebook-sign-in(get)取得Facebook授權網址後,若成功的話,會看到下方允許授權的畫面
首頁畫面
Facebook登入畫面
會出現以下畫面,有稍微看一下審查的說明,基本上如果是開發人員測試用的不需要送審查,功能不會受到影響。
取得Facebook授權資料
取得Facebook授權資料後,Facebook會將我們重新導向到我們設定的重新導向網址 /user/auth/facebook-sign-in-callback(get),我們可以在這個網址中處理回傳授權資料,取得授權資料的控制器會長得向下方這樣
app/Http/Controllers/UserAuthController.php
<?PHP
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use Socialite;
use App\Shop\Entity\User; //使用者 Eloquent ORM Model
class UserAuthController extends Controller
{
//Facebook登入重新導向授權資料處理
public function facebookSignInCallbackProcess()
{
if(request()->error=="access_denied")
{
throw new Exception('授權失敗,存取錯誤');
}
//依照網域產出重新導向連結 (來驗證是否為發出時同一callback)
$redirect_url = env('FB_REDIRECT');
//取得第三方使用者資料
/*
$user = Socialite::driver('facebook')->user();
var_dump($user);
//*/
$FacebookUser = Socialite::driver('facebook')
->fields([
'name',
'email',
])
->redirectUrl($redirect_url)->user();
$facebook_email = $FacebookUser->email;
if(is_null($facebook_email))
{
throw new Exception('未授權取得使用者 Email');
}
//取得 Facebook 資料
$facebook_id = $FacebookUser->id;
$facebook_name = $FacebookUser->name;
echo "facebook_id=".$facebook_id.", facebook_name=".$facebook_name;
//*/
}
}
?>
Facebook只允許指定的網址能夠存取授權資料,所以在取得授權資料時,一樣要設定重新導向的網址是什麼,確認是否有權限取得授權資料,設定完成後使用 ->user() 去取得Facebook使用者資料物件
$redirect_url = env('FB_REDIRECT');
$FacebookUser = Socialite::driver('facebook')
->fields([
'name',
'email',
])
->redirectUrl($redirect_url)->user();
因為我們設定使用者的E-mail為必要欄位,當使用者沒有授權我們存取Email時,我們則會丟出例外,終止Facebook登入程序,若授權成功時,我們將取得Facebook使用者資料中的$facebook_id及$facebook_name用來登入或註冊會員
$facebook_email = $FacebookUser->email;
if(is_null($facebook_email))
{
throw new Exception('未授權取得使用者 Email');
}
//取得 Facebook 資料
$facebook_id = $FacebookUser->id;
$facebook_name = $FacebookUser->name;
操作步驟
首頁,點擊Facebook登入
輸入Facebook帳號密碼
回傳結果,有正確抓到資料
更新Facebook ID或註冊新會員
當取得Facebook授權資料的$facebook_id及$facebook_email後,就要去使用者資料撈取資料,看有沒有已存在的使用者資料,若沒有存在使用者資料,則註冊一筆新的使用者資料
app/Http/Controllers/UserAuthController.php
<?PHP
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use Socialite;
use App\Shop\Entity\User; //使用者 Eloquent ORM Model
class UserAuthController extends Controller
{
//Facebook登入重新導向授權資料處理
public function facebookSignInCallbackProcess()
{
//...以上省略...
$facebook_email = $FacebookUser->email;
if(is_null($facebook_email))
{
throw new Exception('未授權取得使用者 Email');
}
//取得 Facebook 資料
$facebook_id = $FacebookUser->id;
$facebook_name = $FacebookUser->name;
//取得使用者資料是否有此Facebook_id資料
$User = User::where('facebook_id', $facebook_id)->first();
if(is_null($User))
{
//沒有綁定Facebook Id的帳號,透過Email尋找是否有此帳號
$User = User::where('email', $facebook_email)->first();
if(!is_null($User))
{
//有此帳號,綁定Facebook Id
$User->facebook_id = $facebook_id;
$User->save();
}
}
if(is_null($User))
{
//尚未註冊
$input = [
'email' => $facebook_email, //E-mail
'nickname' => $facebook_name, //暱稱
'password' => uniqid(), //隨機產生密碼
'facebook_id' => $facebook_id, //Facebook ID
'type' => 'G', //一般使用者
];
//密碼加密
$input['password'] = Hash::make($input['password']);
//新增會員資料
$User = User::create($input);
//寄送註冊通知信
$mail_binding = [
'nickname' => $input['nickname']
];
Mail::send('email.signUpEmailNotification', $mail_binding,
function($mail) use ($input){
$mail->to($input['email']);
$mail->from('henrychang0202@gmail.com');
$mail->subject('恭喜註冊 Shop Laravel 成功');
});
}
echo "登入成功!";
}
}
?>
在Facebook登入功能時,會優先撈取是否資料庫有對應$facebook_id的使用者資料,若有的話以此筆資料為主,若沒有此$facebook_id的使用者,則會再透過$facebook_email撈取是否資料庫有對應的使用者資料,若有的話則將此$facebook_id綁定更新到這個會員的資料欄位中,這樣下次就可以直接透過$facebook_id取得資料進入登入了。
//取得使用者資料是否有此Facebook_id資料
$User = User::where('facebook_id', $facebook_id)->first();
if(!is_null($User))
{
//沒有綁定Facebook Id的帳號,透過Email尋找是否有此帳號
$User = User::where('email', $facebook_email)->first();
if(!is_null($User))
{
//有此帳號,綁定Facebook Id
$User->facebook_id = $facebook_id;
$User->save();
}
}
當透過$facebook_id及$facebook_email都沒有辦法取得使用者的資料時,表示這位使用者從未註冊過網站的帳號,此時就必須要自動的建立該會員的帳號資料,隨機產生一組密碼,並將該帳號類型設定為一般使用者。當註冊完成後,一樣寄送註冊通知信給該會員,通知已經註冊成功的訊息。
else
{
//尚未註冊
$input = [
'email' => $facebook_email, //E-mail
'nickname' => $facebook_name, //暱稱
'password' => uniqid(), //隨機產生密碼
'facebook_id' => $facebook_id, //Facebook ID
'type' => 'G', //一般使用者
];
//密碼加密
$input['password'] = Hash::make($input['password']);
//新增會員資料
$User = User::create($input);
//寄送註冊通知信
$mail_binding = [
'nickname' => $input['nickname']
];
Mail::send('email.signUpEmailNotification', $mail_binding,
function($mail) use ($input){
$mail->to($input['email']);
$mail->from('henrychang0202@gmail.com');
$mail->subject('恭喜註冊 Shop Laravel 成功');
});
}
信件畫面
Facebook登入網站
不管是$facebook_id及$facebook_email有沒有找到會員資料,若沒有找到也會新增一筆會員資料,為了能夠提高使用者的體驗,在處理完會員資料後,就要立即幫使用者作登入的動作,所以直接使用session()->put()的方法在Session記錄使用者的編號就可以直接登入了,當登入完成後重新導向到首頁即可。
app/Http/Controllers/UserAuthController.php
<?PHP
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Validator; //驗證器
use Hash; //雜湊
use Mail; //寄信
use Socialite;
use App\Shop\Entity\User; //使用者 Eloquent ORM Model
class UserAuthController extends Controller
{
//Facebook登入重新導向授權資料處理
public function facebookSignInCallbackProcess()
{
//...以上省略...
//登入會員
//Session記錄會員編號
session()->put('user_id', $User->id);
//重新導向到原先使用者造訪頁面,沒有嘗試造訪頁則重新導向回首頁
return redirect()->intended('/');
}
?>
小結
在這個社群登入的新的需求案例中,我們可以知道當我們要做資料表的異動時,一樣可以透過資料庫遷移(Migration)來達成資料表的異動,做好有效的資料表版本控管的工作,所以在往後若還有新的需求要做資料表的異動,一樣可以透過這樣的方式去達成資料表異動及管理的效果。
第三方登入幾乎是現在不同專案中必備的功能了,所以Laravel官方也貼心的開發laravel/socialite套件讓我們可以很快速地處理第三方登入的需求。透過這樣的範例也可以很快的了解Laravel如何實作第三方登入的功能。