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

in #kr-dev7 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>

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

Sort:  

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

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

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

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

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

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

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

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

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

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

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

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

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