Web/PHP

[라라벨] 소셜라이트로 OAuth 로그인하기

_sparrow 2020. 4. 11. 00:33
반응형

목표

Passport를 활용한  OAuth 사용도 가능하지만 라라벨 소셜라이트-Socialite를 사용하여 OAuth 인증을 간단하고 편리하게 제공합니다.

Socialite는 현재 페이스북, 트위터, 링크드인, 구글, 깃허브 그리고 Bitbucket을 기본적으로 지원하고 있습니다.

그 외 다른 소셜 로그인(네이버.. 등)도 지원하고 있습니다.

이 글에서는 구글로그인을 해볼 겁니다.

 

이 글에선 OAuth에 대해 상세히 설명하고 있지 않습니다.

OAuth에 대한 자세한 내용은 https://tansfil.tistory.com/58 , https://bcho.tistory.com/913 에서 잘 다루고 있습니다.

환경

php 7.3,  laravel framework 5.5

 

 

 

STEP 1. 구글에 API 등록하기 

구글 클라우드 플랫폼에 접속해서 프로젝트가 없다면 생성해주세요.

햄버거 메뉴를 누르면 API 및 서비스가 보입니다. 클릭해서 들어가 주세요

 

사용자 인증정보를 클릭 후 사용자 인증정보를 만들기 클릭 후 Oauth클라이언트 ID를 클릭해주세요

 

 

웹사이트 인증에 사용할 것이니 웹 애플리케이션 클릭 후 인증정보를 받을 승인된 리디렉션 URI에 각각자의 도메인을 입력해주면 됩니다. 예시로 https://yourwebsite.com/google/callback 처럼 입력해주고 생성!

 

 

STEP 2.  소셜라이트 설치하기


// 소셜라이트를 활용하기위해 컴포저를 활용해 프로젝트에 의존성 패키지를 추가하기
composer require laravel/socialite



 

 

STEP 3. 인증할 소셜 정보 설정하기

// config/services.php

'google' => [
        'client_id' => env('GOOGLE_CLIENT_ID'),         // Your GOOGLE Client ID
        'client_secret' => env('GOOGLE_CLIENT_SECRET'), // Your GOOGLE Client Secret
        'redirect' => env('GOOGLE_REDIRECT'),
    ]
    
//env로 되어있는 내용은 라라벨에서 사용하는  .env 파일에 작성해주면 됩니다.

GOOGLE_CLIENT_ID="example_client_id"
GOOGLE_CLIENT_SECRET="example_client_secret"
GOOGLE_REDIRECT="http://yourwebsite.com/google/callback" // 로그인에 대한 정보를 받을 페이지

OAuth 인증할 플랫폼에 대해 작성해주면 됩니다. 중요한 건 클라이언트 시크릿은 절대 노출되어선 안됩니다.

config.services.php 에서 env로 상세한 데이터가 노출되지 않도록 우회하는 역할을 합니다

 

step1에서 생성했던 OAuth 2.0 클라이언트 ID에서 클라이언트 ID , 클라이언트 보안 비밀을 복사, env파일에 내용을 넣어주면 됩니다. 또한 redirect 주소도 생성했던 승인된 리디렉션 URI과 동일하게 작성해주면 됩니다.

리다이렉트 url은 연습용으로 http도 괜찮지만 보안을 위해서 https 등록해주세요.

Let’s encrypt 인증서 적용하여 HTTPS로 변경하기

 

 

 

 

STEP 4. 라우팅 하기

//소셜 로그인 페이지
Route::get('/login', function () {
    return view('auth/login');
})->name('login');

// 로그인창 가져오기위한 라우터
Route::get('auth/social/google', 'Auth\LoginController@redirectToProvider');

// 로그인 인증후 데이터를 제공해주는 라우터
Route::get('/google/callback', 'Auth\LoginController@handleProviderCallback');

각자의 상황에 맞게 web.php에서 구성을 해주면 됩니다.

 

STEP 5 컨트롤러 만들기

<?php
namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use Socialite;
use Auth;
use App\User;

class LoginController extends Controller
{
    // 1. redirectToProvider() 구글에 로그인요청
    public function redirectToProvider()
    {
    		// 리프레시 토큰을 가져오지않습니다.
//        return Socialite::driver('google')->redirect();
		//리프레시 토큰을 가져오려면 옵션파라미터 'access_type'을 'offline'으로 설정해줘야합니다.
        return Socialite::driver('google')->with(['access_type'=>'offline'])->redirect();
    }

// 2. handleProviderCallback () 로그인한 후에 이미 만들어진 아이디인지 확인후 처리
    public function handleProviderCallback()
    {
        //구글에서 로그인확인후 정보 제공
        $socialUser = Socialite::driver('google')->user();

	// 구글로그인한 유저의 정보를 가져올 수 있습니다.(허용한 한도 내에서)
	dd($socialUser);
		
        // 유저가 이미 회원인지 확인하는 메서드입니다.
        $user = $this->findOrCreateUser($socialUser);

	//$user뒤의 내용을 true로 설정하면 리멤버토큰(자동로그인)이 발급됩니다.
        Auth::login($user, false);

	//토큰을 활용하기위해 로컬에 저장해도 되고 세션에 저장하거나 쿠키에 저장해서 활용할 수 있겠습니다.
        return redirect('/');
        
        페이지를 리다이렉팅되는 페이지를 index로 구성하고 토큰값을 전달합니다.
        // return view('index')->with('access_token',$socialUser->token);
        
    }

    // 아이디 존재하지않으면 새로 생성 하는 메서드
    public function findOrCreateUser($socialUser){
        $existUser = User::where('uid',$socialUser->id)->first();
        if($existUser){
            if($socialUser->refreshToken===null){
                User::where('uid', $existUser->uid)
                    ->update(['name' => $socialUser->getName()],['avatar' =>$socialUser->getAvatar()]);
            }
            else{
                User::where('uid', $existUser->uid)
                    ->update(['name' => $socialUser->getName()],['avatar' =>$socialUser->getAvatar()],['refresh_token'=> $socialUser->refreshToken]);
            }
            // 그전꺼로 로그인 되어있는 정보로 로그인해야함
            return $existUser;
        }
        else{
            $user = User::firstOrCreate([
                'name'  => $socialUser->getName(), //이름가져오기
                'uid'  => $socialUser->getId(), // 구글내부 아이디값 가져오기
                'email' => $socialUser->getEmail(), // 구글 이메일 가져오기
                'avatar' =>$socialUser->getAvatar(), // 구글내 프로필 이미지
                'sns_type'=>'google',
                'refresh_token'=> $socialUser->refreshToken
//            'token'=>$user->token,
            ]);
            return $user;
        }
    }
}

 

회원정보를 저장하기 위해 구글에 등록된 id로 회원정보를 파악했습니다.

Auth를 통해 라라벨 내부에서 인증이 되도록 했습니다.(안 넣어도 됩니다.)

 

STEP 6. 토큰을 통한 사용자 정보 확인하기

Auth를 사용하면 로그인처럼 사용되기 때문에 토큰이 필요하지 않을 수 있지만

토큰을 활용한 정보를 가져오겠다고 하면  아래처럼 사용할 수 있습니다.

 

    public function store(Request $request){
    	//요청에 따라 입력된 정보 확인
        $token = $request->input('token');
        
        //토큰을 사용한 사용자 정보 확인하기
        $user = Socialite::driver('google')->userFromToken($token);
        
        // 사용자정보 노출
        return dd($user);
    }

실제로는 토큰은 보통 보안을 위해서 Bearer authentication이라고 http 인증 헤더로 요청해서 보낸다고 하지만

간단하게 토큰을 바디에 포함해서 보내는 방법을 사용했습니다.

 

정보가 노출되는 dd($user)로 return 했을 때 결과입니다.

 

token이 액세스 토큰이고 refreshtoken은 첫 로그인 시에만 발급됩니다.(더 공부해봐야 할 것 같습니다.)

refresh토큰은 DB에 저장하고 사용했습니다. 액세스 토큰보다 유효기간이 길다고 합니다.

 

백엔드와 프론트 서버가 다르다면 토큰을 전달해줄 방법을 좀 더 생각해봐야 할 것 같습니다.

간편하게 OAuth를 사용해봤는데 이해하는데 정말 긴 시간이 걸렸습니다.

간단하게 로그인으로 사용하기에는 정말 편할 것 같네요

 

개인적으로 OAuth에 대해서 상세하게 따로 공부를 해보시길 바랍니다.

소셜라이트는 OAuth 인증을 위한 방식이 많이 축약되어있습니다.

 

 

반응형