본문 바로가기
세미나

구글 로그인 연동으로 배우는 OAuth 인증 - 2

by 성건희 2019. 5. 15.
반응형

[KISA 핀테크 기술지원센터] 기술세미나 :: 구글 로그인 연동으로 배우는 OAuth 인증 - 2

OAuth과정

  1. Client가 Resource Server에게 '기능 좀 쓰자' 요청

  2. Resource Server가 Client에게 Client_idClient_Secret을 발급

  3. Client는 별도의 저장소에 발급받은 Client_id 와 Client_Secret을 저장해둠

  4. Resource Owner가 Resource Server에게 다음과 같은 메시지 요청

    https://accounts.google.com/o/oauth2/v2/auth?
     scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive.metadata.readonly&
     include_granted_scopes=true&
     state=state_parameter_passthrough_value&
     redirect_uri=http%3A%2F%2Foauth2.example.com%2Fcallback&
     response_type=token&
     client_id=client_id
    
     // client_id에 해당하는 어플리케이션에서 scope에 해당하는 기능만 좀 쓰자
     // Access Token은 redirect_uri 주소로 보내줘
  5. Resource Server가 Resource Owner에게 해당 기능에 대한 권한을 허용할 것인지 물어봄 (Consent Screen)

  6. 허용하면 Resource Server가 redirect_uri에 해당하는 Client에 Access Token을 배달해줌

6번까지 끝낸다음 다시 로그인을 해보면 url에 다음과 같은 정보가 담겨온다.

http://localhost:8887/raw_callback.html#state=state_parameter_passthrough_value&access_token=엑세스토큰정보&expires_in=3600&scope=email%20profile%20https://www.googleapis.com/auth/calendar%20https://www.googleapis.com/auth/userinfo.email%20openid%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&session_state=5b0d22941eafc63b8e97c7ffdc85cef0f57aac3c..1765&prompt=none

#: 영향을 주지않는

  • cf : ? 로 쓰면 실제 데이터를 전달함 (서비스에 영향을 줌)

state : 우리가 준거를 그대로 뱉어냄. 이것을 보고 정말 제대로 된 정보를 받았는지 검증할 수 있음

요청은 하지 않았지만 기본적으로 가지는 scope도 있다.

번외

URI에서 Access Token만 뽑아내는 법

  • 정규화 이용

raw_callback.html 생성 후 다음과 같이 작성

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Document</title>
</head>
<body>
   <h1>Access Token</h1>
    <script>
        var at = location.href.match('access_token=(.+?)&')[1];
        document.write(at);
    </script>
</body>
</html>

정규화에 대한 부가 설명은 생략하도록 한다.

https://www.googleapis.com/oauth2/v1/userinfo?alt=json 접속하면

{
  "error": {
    "code": 401,
    "message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
    "status": "UNAUTHENTICATED"
  }
}

다음과 같이 인증할 수 없다고 나옴.

거의 다왔다!

url 파라미터에 우리의 Access_Token을 넣어주면?

https://www.googleapis.com/oauth2/v1/userinfo?alt=json?access_token=엑세스토큰
{
  "id": "2222222222222222",
  "email": "test@naver.com",
  "verified_email": true,
  "name": "성건희",
  "given_name": "건희",
  "family_name": "성",
  "link": "https://plus.google.com/2222222222222222222",
  "picture": "https://lh4.googleusercontent.com/-d6_wviRTtng/DDDDDDAAAI/DDDGKs/iF12Fb-2Bwk/photo.jpg",
  "locale": "ko"
}

내 소중한 정보를 볼 수 있다.

하지만 URL 상에 Access Token을 보내는 방식은 보안상 좋지 않다.

# library 방식

구글 OAuth 메뉴얼의 Complete Example 코드를 복사 후 lib.html 생성 후 붙여넣는다.

Client_id 와 SCOPE를 수정해준다.

<script>
  var GoogleAuth;
  var SCOPE = 'https://www.googleapis.com/auth/calendar';
  function handleClientLoad() {
    // Load the API's client and auth2 modules.
    // Call the initClient function after the modules load.
    gapi.load('client:auth2', initClient);
  }

  function initClient() {
    // Retrieve the discovery document for version 3 of Google Drive API.
    // In practice, your app can retrieve one or more discovery documents.
    var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/drive/v3/rest';

    // Initialize the gapi.client object, which app uses to make API requests.
    // Get API key and client ID from API Console.
    // 'scope' field specifies space-delimited list of access scopes.
    gapi.client.init({
        'apiKey': 'YOUR_API_KEY',
        'discoveryDocs': [discoveryUrl],
        'clientId': '898088711348-0bg7rc6abjssqiitkecq50tmnmq65ls0.apps.googleusercontent.com',
        'scope': SCOPE
    }).then(function () {
      GoogleAuth = gapi.auth2.getAuthInstance();

      // Listen for sign-in state changes.
      GoogleAuth.isSignedIn.listen(updateSigninStatus);

      // Handle initial sign-in state. (Determine if user is already signed in.)
      var user = GoogleAuth.currentUser.get();
      setSigninStatus();

      // Call handleAuthClick function when user clicks on
      //      "Sign In/Authorize" button.
      $('#sign-in-or-out-button').click(function() {
        handleAuthClick();
      }); 
      $('#revoke-access-button').click(function() {
        revokeAccess();
      }); 
    });
  }

  function handleAuthClick() {
    if (GoogleAuth.isSignedIn.get()) {
      // User is authorized and has clicked 'Sign out' button.
      GoogleAuth.signOut();
    } else {
      // User is not signed in. Start Google auth flow.
      GoogleAuth.signIn();
    }
  }

  function revokeAccess() {
    GoogleAuth.disconnect();
  }

  function setSigninStatus(isSignedIn) {
    var user = GoogleAuth.currentUser.get();
    var isAuthorized = user.hasGrantedScopes(SCOPE);
    if (isAuthorized) {
      $('#sign-in-or-out-button').html('Sign out');
      $('#revoke-access-button').css('display', 'inline-block');
      $('#auth-status').html('You are currently signed in and have granted ' +
          'access to this app.');
    } else {
      $('#sign-in-or-out-button').html('Sign In/Authorize');
      $('#revoke-access-button').css('display', 'none');
      $('#auth-status').html('You have not authorized this app or you are ' +
          'signed out.');
    }
  }

  function updateSigninStatus(isSignedIn) {
    setSigninStatus();
  }
</script>

<button id="sign-in-or-out-button"
        style="margin-left: 25px">Sign In/Authorize</button>
<button id="revoke-access-button"
        style="display: none; margin-left: 25px">Revoke access</button>

<div id="auth-status" style="display: inline; padding-left: 25px"></div><hr>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<script async defer src="https://apis.google.com/js/api.js" 
        onload="this.onload=function(){};handleClientLoad()" 
        onreadystatechange="if (this.readyState === 'complete') this.onload()">
</script>

OAuth의 승인 방식 종류

여러가지 승인 방식이 있지만 대표적인 2가지만 소개

  • Implicit Grant Type : 암시적 승인
    • 우리가 지금까지 실습해온 방식
    • 위험함 (OAuth 공식 메뉴얼에서도 추천하지 않음)
  • Authorization Code Grant Type : 권한 부여 코드 승인 타입
    • Resource Server가 Client에게 Access Token을 주지 않고 CODE라는 녀석을 줌
    • Client가 Resource Server에게 정보를 제출 : Client_id, Client_secret, CODE
    • 그 뒤 Resource Server가 일치하는지 판별 후 일치하면 Access Token을 전송
반응형

댓글