스팀커넥트2 강좌 :: OAuth Redirect 후 처리, 로그아웃

in kr-dev •  7 years ago  (edited)

지난 강좌
스팀커넥트2 강좌 :: 개발환경 설정, 스팀 아이디로 로그인하기 버튼 만들기


지난시간에 만든 로그인 버튼을 누르면 steemconnect.com 으로 가서 퍼미션을 확인합니다.
sc2oauth.png
무슨무슨 퍼미션을 허용할 지는 sc2.Initialize 에서 scope 배열에 설정합니다.
['login', 'offline', 'vote', 'comment', 'comment_delete', 'comment_options', 'custom_json', 'claim_reward_balance']
각 scope 의 의미는 링크 참조.
https://github.com/steemit/steemconnect/wiki/OAuth-2#scopes

스팀커넥트에서 로그인 디테일을 입력하고 나면 아래와같은 형식의 URL 로 돌아옵니다.

http://localhost:8080/?access_token=eyJhbGciOiJIUzI1NiIs1nR5cCI6IkpXVCJ9.eyJyb2xlIjoiYXBaIiwicHJveHkiOiJzYzJ0dxqiLCJ1c2VyIjoibW9ybmloZyIsInNjb3BiijpbxnGgdGUiLCJjb21txW50Il0sImlhdCI6MTUxNzk2MDU1NiwiBXhwIjoxNTE4NTY1MzU2fQ.1GJx2WHNL3DJ4f6RB3vS3i3t-3BZ3HrKcZJoM_hi0aI&expires_in=604800&username=morning

URL 파라미터에 있는 3가지

access_token 입력한 스팀 아이디와 비밀번호로 로그인에 성공했다는 증표 토큰입니다. 이것이 있어야 보팅, 포스팅 등의 API call 이 성공할 수 있습니다.
expires_in access_token이 만료되기 까지의 초단위 숫자 입니다.
username 로그인 된 스팀 아이디 입니다.

이제 웹페이지가 로드 될 때, 보통의 로딩인지 OAuth 에서 redirect 되는 로딩인지 구분해서 처리해야 합니다.
URL 파라미터에 access_token 이 있는지를 가지고 구분합니다.
우선 함수하나 정의해놓고

function getParameter(paramName) {
    var searchString = window.location.search.substring(1);
    var params = searchString.split('&');
    var i, val;

    for (i = 0; i < params.length; i++) {
        val = params[i].split('=');
        if (val[0] == paramName) {
            return val[1];
        }
    }
    return null;
}

파라미터에 access_token 이 있을 경우 로컬 스토리지에 저장하고 다시 access_token 파라미터 없이 리프레쉬 합니다.

if (getParameter('access_token') !== null) {
    // access_token 파라미터가 있는 경우
    localStorage.setItem('access_token', getParameter('access_token'));
    localStorage.setItem('expires_in', getParameter('expires_in'));
    localStorage.setItem('auth_timestamp', Math.round(Date.now()/1000));
    localStorage.setItem('username', getParameter('username'));

    // 브라우저 리프레쉬를 하므로 이 다음 라인은 실행되지 않음
    window.location.href = '//' + location.host + location.pathname;
}

// access_token 파라미터가 없는 경우
var callbackURL = location.protocol + '//' + location.host + location.pathname;
var accessToken = localStorage.getItem('access_token');
var expiresIn = localStorage.getItem('expires_in');
var authTimestamp = localStorage.getItem('auth_timestamp');
var logoutButton = document.querySelector('.logout');
var loginButton = document.querySelector('.login');
var api;

if (accessToken !== null) {
    // 이전에 저장된 액세스토큰이 있는 경우
    api = sc2.Initialize({
        app: 'sc2tut',
        callbackURL: callbackURL,
        accessToken: accessToken,
        scope: ['vote', 'comment']
    });
    // 로그아웃 버튼 보이기
    logoutButton.style.display = 'block';
    loginButton.style.display = 'none';

    // 로그아웃 클릭 처리

} else {
    // 이전에 로그인 한 적이 없어서 저장된 액세스토큰이 없는 경우
    api = sc2.Initialize({
        app: 'sc2tut',
        callbackURL: callbackURL,
        scope: ['vote', 'comment']
    });
    // 로그인 버튼 보이기
    logoutButton.style.display = 'none';
    loginButton.style.display = 'block';

    // 로그인 링크 설정
    var link = api.getLoginURL();
    console.log('SteemConnect2 getLoginURL:', link);
    loginButton.setAttribute('href', link);
}

여기까지 하면 로그인 리다이렉트 후에 로그인 버튼이 안보이고 로그아웃 버튼이 보이게 되며
브라우저 리프레쉬를 해도 로그아웃 버튼이 보이게 됩니다.

로그아웃

이어서 로그아웃 클릭 처리 부분을 알아봅니다.

// 로그아웃 클릭 처리
loginButton.addEventListener('click', function(e) {
    e.preventDefault();

    api.revokeToken(function (err, res) {
        console.log(err, res);
        localStorage.removeItem('access_token');
        localStorage.removeItem('expires_in');
        localStorage.removeItem('username');
        localStorage.removeItem('auth_timestamp');

        logoutButton.style.display = 'none';
        loginButton.style.display = 'block';
        var link = api.getLoginURL();
        loginButton.setAttribute('href', link);
    });
});

revokeToken() 은 주어진 액세스토큰을 못쓰게 해달라고 스팀커넥트 서버에 요청하는 함수입니다.
콜백함수 결과는 {success: true} 입니다.

expires_in : 액세스토큰 유통기한

다음으로 expires_in 을 어떻게 활용해야 하는지 알아봅니다.
expires_in은 액세스토큰의 유통기한입니다. 기한이 지나고 나면 액세스토큰이 더이상 통하지 않게 되어서 보팅이나 포스팅을 하려고 했을 때 실패하게 됩니다.
매번 시간을 계산해서 유통기한이 지났으면 로그아웃 된 것으로 처리를 해줘야 합니다.
로직은 OAuth 성공시의 타임스탬프를 로컬스토리지에 저장해두고
액세스토큰 유효성 체크할 때 아래와 같이 합니다.

var currentTimestamp = Math.round(Date.now()/1000);
if (currentTimestamp - authTimestamp >= expiresIn) {
    // 액세스토큰 유효기한이 지나서 로그인 풀림
} else {
    // 액세스토큰 유효해서 로그인 된 상태
}

여기까지 해서 전체 HTML/JavaScript 소스코드 첨부합니다.

<!doctype html>
<html lang="en">
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
  </head>
  <body>
    <h1>SteemConnect2 Tutorial</h1>
    <a href="#" class="login">Login with Steem</a>
    <a href="#" class="logout">Logout</a>
    <script src="sc2.min.js"></script>
    <script>
    function getParameter(paramName) {
        var searchString = window.location.search.substring(1);
        var params = searchString.split('&');
        var i, val;

        for (i = 0; i < params.length; i++) {
            val = params[i].split('=');
            if (val[0] == paramName) {
                return val[1];
            }
        }
        return null;
    }

    if (getParameter('access_token') !== null) {
        localStorage.setItem('access_token', getParameter('access_token'));
        localStorage.setItem('expires_in', getParameter('expires_in'));
        localStorage.setItem('auth_timestamp', Math.round(Date.now()/1000));
        localStorage.setItem('username', getParameter('username'));
        window.location.href = '//' + location.host + location.pathname;
    }

    var callbackURL = location.protocol + '//' + location.host + location.pathname;
    var accessToken = localStorage.getItem('access_token');
    var expiresIn = localStorage.getItem('expires_in');
    var authTimestamp = localStorage.getItem('auth_timestamp');
    var api;
    var logoutButton = document.querySelector('.logout');
    var loginButton = document.querySelector('.login');
    var currentTimestamp = Math.round(Date.now()/1000);

        if (currentTimestamp - authTimestamp >= expiresIn) {
            // 액세스토큰 유효기한 만료
            localStorage.removeItem('access_token');
            localStorage.removeItem('expires_in');
            localStorage.removeItem('username');
            localStorage.removeItem('auth_timestamp');

      api = sc2.Initialize({
        app: 'sc2tut',
        callbackURL: callbackURL,
        scope: ['vote', 'comment']
      });
      // 로그인 버튼 보이기
      logoutButton.style.display = 'none';
      loginButton.style.display = 'block';

      // 로그인 링크 설정
      var link = api.getLoginURL();
      loginButton.setAttribute('href', link);
        } else {
      // 액세스토큰 유효
      if (accessToken !== null) {
        // 이전에 저장된 액세스토큰이 있는 경우
        api = sc2.Initialize({
            app: 'sc2tut',
            callbackURL: callbackURL,
            accessToken: accessToken,
            scope: ['vote', 'comment']
        });
        // 로그아웃 버튼 보이기
        logoutButton.style.display = 'block';
        loginButton.style.display = 'none';

        // 로그아웃 클릭 처리
        logoutButton.addEventListener('click', function(e) {
            e.preventDefault();

            api.revokeToken(function (err, res) {
                console.log(err, res);
                localStorage.removeItem('access_token');
                localStorage.removeItem('expires_in');
                localStorage.removeItem('username');
                localStorage.removeItem('auth_timestamp');

                logoutButton.style.display = 'none';
                loginButton.style.display = 'block';
                var link = api.getLoginURL();
                loginButton.setAttribute('href', link);
            });
        });
      } else {
        // 이전에 로그인 한 적이 없어서 저장된 액세스토큰이 없는 경우
        api = sc2.Initialize({
            app: 'sc2tut',
            callbackURL: callbackURL,
            scope: ['vote', 'comment']
        });
        // 로그인 버튼 보이기
        logoutButton.style.display = 'none';
        loginButton.style.display = 'block';

        // 로그인 링크 설정
        var link = api.getLoginURL();
        console.log('SteemConnect2 getLoginURL:', link);
        loginButton.setAttribute('href', link);
      }
    }

    if (accessToken) {
      var username = localStorage.getItem('username');
      console.log('Hi, ', username);
    }
    </script>
  </body>
</html>

다음시간에는 스팀커넥트로 보팅 하는 방법을 알아봅니다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!
Sort Order:  

좋은 글 감사합니다 ~ 잘 참고 하겠습니다 !!

Nice post

지금 steemit을위한 아주 좋은 게시물

훌륭한 글에는 보팅이죠!! 좋은글 감사합니다

잘보고 공부 하겠습니다. 감사합니다.

ㅠ으아 문송합니다ㅠㅠ
좋은 글 감사합니다ㅠㅠ

이해하고 싶은데 못하는 심정...

ㅜ0ㅜ 워.. 너무 고생하셔서 설명해 주셨는데
머리에 막 지진이 나고 있어요 ㅠㅠㅠㅠㅠ

다 이해했어....;;;;;;ㅠ 라고 하고싶다..

아 멋지다. 코딩하는 사람...;

코딩하시는 분들 넘 신기해요. 마법의 언어를 본 것 같습니다.

필요하고 중요한 글인것 같은데... 이해가 하...ㅠㅠ
스팀잇하시는분들의 수준이 정말 높은것 같아요...

OAuth 래퍼 하나 만들어야겠군요 ㅎㅎ
좋은 가이드 감사합니다 :)

열심히 공부하는법밖엔 없네요.
좋은글 감사합니다.