라라벨 프로젝트에서 소셜 로그인 기능을 구현해본다. 기본적으로 공식지원하는 socialite라는 패키지가 있다. 이걸 이용해서 구글, 페이스북, 트위터, 깃허브 등 주요 서비스업체의 계정으로 우리가 만든 서비스에 로그인하도록 할 수 있다. 


이들 서비스 외에 카카오나 네이버 로그인을 하고 싶다면 laravel socialite를 확장한 socialite provider를 별도로 설치해야 한다. 네이버카카오용 provider를 설치하고 매뉴얼에 따라 진행하면 된다. 다만 그 세팅 및 사용법이 약간 다를 수 있다.


일단 여기서는 페이스북을 통한 로그인을 해보도록 하자. 




1. composer를 통한 신규 프로젝트 설치


먼저 새로운 프로젝트를 하나 생성한다. 일반적인 프로젝트의 생성과 세팅은 이전 포스팅에서 설명한 방식 및 절차와 동일하므로 해당 포스팅을 참고하면 되겠다. 



아래와 같이 socialApp이라는 이름으로 하나의 프로젝트를 생성한다.


$ composer create-project laravel/laravel socialApp --prefer-dist -vvv




2. socialite 설치


프로젝트를 생성했으면 이제 소셜 로그인 연동을 위한 패키지인 socialite를 추가로 설치한다. socialite는 라라벨에서 공식적으로 지원하는 패키지로 이 패키지를 이용하면 손쉽게 소셜 로그인 기능을 구현할 수 있다. 


$ composer require laravel/socialite


socialite 설치 후 config/services.php 파일에 몇 가지 설정을 추가한다. 소셜 로그인 기능은 OAuth2를 이용하기 때문에 페이스북에 있는 내 계정을 이용해 내가 만든 웹서비스에서 로그인을 할 수 있도록 하겠다면 다음의 3가지가 필요하게 된다. 


1. client id

2. client secret

3. redirect url


위의 3가지 항목이 뭔지는 OAuth 2.0 에 대한 이해가 필요하기 때문에 여기서 따로 설명하지 않을 것이다. 하지만 이미 구글링을 통해 OAuth 2에 대한 충분히 많은 설명 문서를 볼 수 있으니 찾아보도록 하자.


일단 여기서는 services.php 파일에 페이스북 소셜로그인 연동을 위한 3가지 항목값을 환경설정파일(.env)에서 가져오겠다고 세팅한다. 


'facebook' => [
   'client_id' => env('FACEBOOK_CLIENT_ID'),
   'client_secret' => env('FACEBOOK_CLIENT_SECRET'),
   'redirect' => env('FACEBOOK_REDIRECT')
],


여기서 facebook이라는 이름은 socialite 패키지를 이용하기 때문에 이미 정해진 이름이다. 페이스북 외에도 twitter, linkedin, google, github 등을 지정해 해당 서비스를 이용한 소셜 로그인기능을 구현할 수 있다. 


여기서는 env() 헬퍼를 통해 이들 값을 프로젝트 환경설정 파일에서 가져오겠다고 하였다. 따라서 환경설정 파일에는 이들 항목의 값이 설정되어 있어야 한다. 


FACEBOOK_CLIENT_ID=클라이언트ID
FACEBOOK_CLIENT_SECRET=클라이언트비밀키
FACEBOOK_REDIRECT=http://localhost/facebook/callback


클라이언트ID와 비밀키는 페이스북에 내가 앱을 등록하면 얻을 수 있다. 




3. 페이스북에서 앱  만들기


페이스북 개발자센터(https://developers.facebook.com/?locale=ko_KR)에서 소셜 로그인을 위해 앱을 생성한다. 



필자는 이미 2개의 앱이 등록되어 있다. 여기서 새 앱 추가를 클릭하면 새로운 앱을 만들 수 있는데 이렇게 해서 만들어진 앱을 보면 다음과 같이 앱 ID와 시크릿코드가 페이스북으로부터 부여되어 있는 것을 알 수 있다. 



이 앱 ID와 앱 시크릿 코드를 환경설정파일(.env)에 적어주면 된다. 





4. socialite 세팅


socialite 설치 후 내가 만든 웹사이트에서 이 패키지를 사용할 수 있도록 하기 위해 몇가지 세팅을 해준다. 


config/app.php 파일을 열어 providers 배열에 socialite 패키지를 추가해 준다. 


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


aliases 배열에도 Socialite라는 이름으로 별칭을 추가해 준다.


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




5. 인증기능 추가


라라벨에서 기본 제공하는 인증기능을 사용하기 위해 추가해준다. 


$ php artisan make:auth


별도로 로그인 기능을 추가할 수 도 있지만 여기서는 페이스북으로 로그인하기 구현에만 집중하기 위해 인증기능을 별도로 개발하지 않고 기본 제공되는 컨트롤러와 페이지 등을 사용할 것이다. 


인증기능을 가져왔으면 기본 제공되는 migration을 실행해 인증에 필요한 관련 테이블 등이 미리 생성되도록 해야 한다.  이 부분은 기본 라라벨 프로젝트 준비하기에서 설명했던 부분이라 따로 설명하진 않겠다. 





6. 라우팅 추가


이제 2개의 라우팅이 필요하다. 하나는 페이스북 앱을 등록할 당시 입력했던 redirect url에 대한 콜백 라우팅이고 다른 하나는 페이스북으로 로그인하기 버튼을 클릭했을 때 실행되는 url이다.  


// Social 로그인
Route::get('/{site}/redirect', ['as' => 'redirect', 'uses' => 'Auth\LoginController@redirectToProvider']);
Route::get('/{site}/callback', ['as' => 'callback', 'uses' => 'Auth\LoginController@handleProviderCallback']);


기본 제공되는 인증 라우팅외에 방금 추가한 2개의 라우팅이 보일 것이다.



라라벨이 기본 제공하는 인증기능에 LoginController가 이미 있으므로 여기에 메소드를 추가한다. 


<?php namespace App\Http\Controllers\Auth; use App\Http\Controllers\Controller; use Illuminate\Foundation\Auth\AuthenticatesUsers; class LoginController extends Controller { /* |-------------------------------------------------------------------------- | Login Controller |-------------------------------------------------------------------------- | | This controller handles authenticating users for the application and | redirecting them to your home screen. The controller uses a trait | to conveniently provide its functionality to your applications. | */ use AuthenticatesUsers; /** * Where to redirect users after login. * * @var string */ protected $redirectTo = '/home'; /** * Create a new controller instance. * * @return void */ public function __construct() { $this->middleware('guest')->except('logout'); } public function redirectToProvider($site) { return Socialite::driver($site)->redirect(); } public function handleProviderCallback($site) { Log::info("===== 소셜 로그인 (" . $site . ") ====="); try { $user = Socialite::driver($site)->user(); } catch (\Exception $e) { return redirect('/'); } $existingUser = User::where('email', $user->email)->first(); if($existingUser) { Log::info("이미 가입한 소셜 로그인 사용자"); auth()->login($existingUser, true); } else { if(isset($user->email)) { $newUser = new User(); $newUser->name = $user->name; $newUser->email = $user->email; $newUser->password = bcrypt('1234'); $newUser->save(); Log::info("신규 가입한 소셜 로그인 사용자"); Log::info($newUser); auth()->login($newUser, true); } } return redirect()->to('/home'); } } ?>


로그인하기 버튼을 클릭하면 redirectToProvider() 메소드가 실행되는데 여기서 페이스북으로 로그인을 하게 된다. 이때 페이스북으로는 호출하려는 앱의 ID와 시크릿 코드, 그리고 페이스북으로부터 코드(Authorization Code라고 한다)를 돌려받기 위한 redirect url을 전송해야 한다. 그러면 페이스북은 적절한 처리를 끝내고 redirect url을 호출할 때 쿼리스트링에 권한 코드를 붙여서 보내주는데 이렇게 받은 코드를 가지고 다시 페이스북에 요청을 하게 되면 그때 페이스북 api를 호출하는데 필요한 토큰(token)과 이 토큰이 만료되었을 때 재발급받는데 필요한 리프레시 토큰(refresh token)을 얻을 수 있게 된다. 자세한 내용은 OAuth2에 대해 구글링해보기를 추천한다. 


라라벨이 기본으로 제공하는 인증관련 테이블 중에 사용자 정보를 담고 있는 Users 테이블은 이미 이메일을 고유키로 하므로 여기서는 페이스북 로그인을 통해 얻은 이메일이 등록되어 있지 않으면 신규 사용자로 등록한 후 로그인시키고, 이미 존재하는 경우에는 바로 로그인시키도록 한다. 


우선 뷰(블레이드) 파일에 페이스북으로 로그인하기 버튼을 추가해준다.

   
<?php
<div class="form-group row mb-0">
    <div class="col-md-12 text-center">
        <a href="{{ route('redirect', ['facebook']) }}" class="btn btn-primary">Login with Twitter</a>
    </div>
</div>
?>

페이스북 외에도 구글이나 카카오, 네이버 등 유명한 다른 업체를 통한 인증버튼이 추가될 가능성이 매우 크므로 앞서 redirect 메소드는 사이트를 식별할 수 있는 인자를 인자를 받도록 하였다. 


이제 로그인 화면에서 페이스북으로 로그인하기 버튼을 클릭한다.



로그인 버튼을 클릭하면 우리가 방금 만든 socialApp에서 페이스북 사용자의 이름과 이메일 주소 등 프로필 정보를 요청한다는 내용과 함께 페이스북 사용자에게 이를 허용할 것인지를 묻는다. 웹사이트에서 요청한 권한을 허락할지 말지는 페이스북 계정 사용자가 결정한다. 



여기서 허용하게 되면 우리가 앞서 세팅한 앱 ID와 시크릿 코드를 페이스북에 전송하여 권한을 요청하게 된다. 페이스북은 우리가 제출한 앱 ID와 시크릿 코드, 그리고 페이스북에서 앱을 만들 당시 등록한 redirect url이 우리가 전송한 값과 일치하는지 검증을 하고 만일 일치할 경우 코드를 생성하여 우리에게 돌려준다. 돌려주는 방법은 redirect url을 호출할 때 쿼리스트링으로 넘겨주는 방식이다. 


그리고 이렇게 넘겨받은 권한 코드로 다시 추가 요청을 하게 되면 비로소 토큰을 얻을 수 있게 되는데 이 토큰을 사용해 페이스북 사용자의 프로필 정보를 가져올 수 있게 되며 socialite가 이러한 과정을 쉽게 처리할 수 있도록 해주는 역할을 한다.  


이렇게 가져온 사용자의 이메일이 우리 users 테이블에 없다면 신규가입처리한 후 로그인시키고 만일 이미 존재한다면 바로 로그인을 시킨다. 


Posted by 라스모르
,