1. 세션을 시작한다.
session_start();
2. 구글에 등록해놓은 정보들을 이용해서 로그인해야 하므로, 변수에 잘 저장해 놓자.
$g["client_id"] = '483---.apps.googleusercontent.com';
$g["client_secret"] = 'JVa---c5vILY0';
$g["redirect_uri"] = 'http://www.mysite.co.kr/callback-google.php';
3. 구글로 로그인하는 버튼을 만들고, 거기에 링크를 걸어준다.
if( !isset($_SESSION['state']) )
$_SESSION['state'] = urlencode( md5( microtime().mt_rand() ) );
$login_url =
"https://accounts.google.com/o/oauth2/auth?".
"response_type=token".
"&passive=true".
"&client_id=" . $g["client_id"] .
"&state=" . $_SESSION['state'] .
"&redirect_uri=" . urlencode( $g["redirect_uri"] ) .
"&scope=" . urlencode( "openid email" );
echo "<br><a href='". $login_url ."'> Google+ 계정으로 로그인 </a><br>";
4. 사용자가 로그인 버튼을 클릭하면 Google 사이트로 이동해서 로그인하는 과정을 거친다.
로그인이 끝나면 callback uri에 적어놓은 주소로 사용자가 이동해 들어오게 되는데, 다음과 같은 주소를 가지고 들어온다.
http://www.mysite.co.kr/callback-google.php#
state=ouFvDAK6---&access_token=ya29---&
token_type=Bearer&
expires_in=3600&
authuser=0&
num_sessions=1&
hd=mysite.com&
session_state=826dd---&
prompt=none
그런데 이 주소에 #이 사용되었기때문에 서버에서는 #을 포함해 그 뒷부분에 무엇이 있는지 알 수가 없다. 그래서, #이후의 정보에 접근할 수 있는 브라우저에서 javascript를 실행시켜야 한다.
<script>
location.href = 'http://www.mysite.co.kr/callback-google.php?hash=1&' +
location.hash.substring(1);
</script>
5. 사용자는 Javascript의 location.href 변경을 통해서 웹서버로 다시 찾아오게 된다. Javascript 덕분에 이제 모든 파라미터들을 php에서도 읽을 수 있게 되었다. 파라미터 중에 access_token이 있는지 여부에 따라 처리가 달라져야 한다.
if( isset( $_GET["access_token"] ) ) {
// 사용자가 정보공유를 허가한 경우이다
$_SESSION['access_token'] = $_GET['access_token'];
$_SESSION['token_type'] = $_GET['token_type'];
$_SESSION['expires_at'] = $_GET['expires_in'] + microtime(true);
validate_token_info();
}
else {
// 사용자가 정보공유를 불허한 경우이다
}
validate_token_info()에서는 사용자의 email 주소를 알아낸다.
function validate_token_info() {
$url = "https://www.googleapis.com/oauth2/v1/tokeninfo?" .
"access_token=" . $_SESSION["access_token"];
$c = curl_init();
curl_setopt($c, CURLOPT_URL, $url);
curl_setopt($c, CURLOPT_RETURNTRANSFER, true);
$r = curl_exec($c);
curl_close($c);
$j = json_decode($r, true);
$_SESSION['userid'] = $j["email"] ?
$j["email"] : "nothing";
}
(token info의 예)
{
"iss":"accounts.google.com",
"at_hash":"HK6E_P6Dh8Y93mRNtsDB1Q",
"email_verified":"true",
"sub":"10769150350006150715113082367", ==> 사용자의 이메일주소는 변할지언정 sub값은 평생토록 변하지 않는다
"azp":"1234987819200.apps.googleusercontent.com",
"email":"jsmith@example.com", ==> 유일하지 않은 값이다. 중복될 수 있다.
"aud":"1234987819200.apps.googleusercontent.com",
"iat":1353601026,
"exp":1353604926 ==> id token이 폐기되는 시각
}
6. Access Token 폐기시키는 방법
Access Token을 폐기시킨다고 해서 서비스에서 로그아웃 되는것은 아니다.
if( isset( $_SESSION['access_token'] ) ) {
$url = "https://accounts.google.com/o/oauth2/revoke?".
"token=".$_SESSION['access_token'];
echo "<br><a href='". $url ."'> Access Token 폐기 </a><br>";
}
{
"iss":"accounts.google.com",
"at_hash":"HK6E_P6Dh8Y93mRNtsDB1Q",
"email_verified":"true",
"sub":"10769150350006150715113082367", ==> 사용자의 이메일주소는 변할지언정 sub값은 평생토록 변하지 않는다
"azp":"1234987819200.apps.googleusercontent.com",
"email":"jsmith@example.com", ==> 유일하지 않은 값이다. 중복될 수 있다.
"aud":"1234987819200.apps.googleusercontent.com",
"iat":1353601026,
"exp":1353604926 ==> id token이 폐기되는 시각
}
6. Access Token 폐기시키는 방법
Access Token을 폐기시킨다고 해서 서비스에서 로그아웃 되는것은 아니다.
if( isset( $_SESSION['access_token'] ) ) {
$url = "https://accounts.google.com/o/oauth2/revoke?".
"token=".$_SESSION['access_token'];
echo "<br><a href='". $url ."'> Access Token 폐기 </a><br>";
}
구글 계정으로 로그인하는 방법을 사용해보니, 맺고 끊음이 불분명한 것이 치명적인 약점으로 작용함을 알겠더라. 사용자에게 비밀번호를 한 번 더 입력하라는 요구를 하고싶어도 그것이 불가능한 것이 바로 이 "남의 서비스 계정으로 내 서비스에 로그인하기"의 세계다.
세상에 완벽하게 좋은 공짜는 없어!