From 5b7eba61cc23baead806a7f12b76810c48173b9b Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 9 Sep 2018 15:54:17 +0900 Subject: [PATCH 1/7] =?UTF-8?q?=EB=B0=98=EA=B3=84=EC=97=90=20'=EB=8F=99?= =?UTF-8?q?=EA=B7=B8=EB=9D=BC=EB=AF=B8'=20=EC=98=A4=ED=83=80=20=EC=A0=9C?= =?UTF-8?q?=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- hwe/sammo/WarUnitGeneral.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hwe/sammo/WarUnitGeneral.php b/hwe/sammo/WarUnitGeneral.php index a59c859d..56877049 100644 --- a/hwe/sammo/WarUnitGeneral.php +++ b/hwe/sammo/WarUnitGeneral.php @@ -784,7 +784,7 @@ class WarUnitGeneral extends WarUnit{ foreach($table as $skillKey => $skillMultiply){ if($oppose->hasActivatedSkill($skillKey)){ $josaUl = \sammo\JosaUtil::pick($skillKey, '을'); - $thisLogger->pushGeneralBattleDetailLog("반계로 상대의 {$skillKey}{$josaUl} 되돌렸다!"); + $thisLogger->pushGeneralBattleDetailLog("반계로 상대의 {$skillKey}{$josaUl} 되돌렸다!"); $opposeLogger->pushGeneralBattleDetailLog("{$skillKey}{$josaUl} 역으로 당했다!"); $this->multiplyWarPowerMultiply($skillMultiply); From 15d43c9653ff052a04603af57f29bbaf0cde3b44 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 9 Sep 2018 20:19:00 +0900 Subject: [PATCH 2/7] =?UTF-8?q?=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=B4=88=EA=B8=B0=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- css/login.css | 4 ++ index.php | 51 ++++++++++++--- j_login.php | 96 ++++++++++++++++++++++++++++- js/join.js | 2 +- js/login.js | 37 +++++++++-- oauth_kakao/j_change_pw.php | 2 +- oauth_kakao/j_check_OTP.php | 92 +++++++++++++++++++++++++++ oauth_kakao/j_join_process.php | 21 +++++-- oauth_kakao/j_login_oauth.php | 86 ++++++++++++++++++++++---- oauth_kakao/lib.join.php | 66 +++++++++++++++++++- oauth_kakao/oauth.php | 9 ++- src/kakao/Kakao_REST_API_Helper.php | 22 ++++--- src/sammo/Session.php | 17 ++++- 13 files changed, 458 insertions(+), 47 deletions(-) create mode 100644 oauth_kakao/j_check_OTP.php diff --git a/css/login.css b/css/login.css index 3232b9a7..d8c3d4ff 100644 --- a/css/login.css +++ b/css/login.css @@ -98,6 +98,10 @@ input::-webkit-input-placeholder { z-index:800; } +#login_card{ + z-index:801; +} + #btn_kakao_login{ cursor: pointer; height:46px; diff --git a/index.php b/index.php index 9b50cd88..d3ddb6bd 100644 --- a/index.php +++ b/index.php @@ -81,12 +81,18 @@ function doLoginUsingOAuth(){ url:'oauth_kakao/j_login_oauth.php', dataType:'json' }).then(function(obj){ - if(!obj.result){ - alert(obj.reason); - } - else{ + if(obj.result){ window.location.href = "./"; + return; } + if(!obj.reqOTP){ + alert(obj.reason); + return; + } + $('#modalOTP').modal().on('shown.bs.modal', function(){ + $('#otp_code').focus(); + }); + }); } @@ -126,7 +132,7 @@ function postOAuthResult(result){

삼국지 모의전투 HiDCHe

-
+

로그인

@@ -152,7 +158,7 @@ function postOAuthResult(result){
-
+
@@ -172,9 +178,40 @@ function postOAuthResult(result){
-
개인정보처리방침 & 이용약관
© 2018 • HideD
크롬과 파이어폭스에 최적화되어있습니다.
+
+ + + diff --git a/j_login.php b/j_login.php index 3aeecc99..fb18c875 100644 --- a/j_login.php +++ b/j_login.php @@ -2,7 +2,9 @@ namespace sammo; require(__dir__.'/vendor/autoload.php'); +require(__dir__.'/oauth_kakao/lib.join.php'); +use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper; $RootDB = RootDB::db(); $session = Session::getInstance(); @@ -16,12 +18,86 @@ $password = Util::getReq('password'); if(!$username || !$password){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'올바르지 않은 입력입니다.' ]); } +function kakaoOAuthCheck(array $userInfo) : ?array { + + if(!\kakao\KakaoKey::REST_KEY){ + return [false, '카카오 API 앱이 등록되지 않았습니다. 관리자에게 문의해 주세요.']; + } + + $oauthID = $userInfo['oauth_id']; + $oauthInfo = Json::decode($userInfo['oauth_info'])??[]; + if(!$oauthInfo){ + return [false, 'OAuth 정보가 보관되어 있지 않습니다. 카카오 로그인을 수행해 주세요.']; + } + + $accessToken = $oauthInfo['accessToken']??null; + $refreshToken = $oauthInfo['refreshToken']??null; + $accessTokenValidUntil = $oauthInfo['accessTokenValidUntil']??null; + $refreshTokenValidUntil = $oauthInfo['refreshTokenValidUntil']??null; + $OTPValue = $oauthInfo['OTPValue']??null; + $OTPTrialUntil = $oauthInfo['OTPTrialUntil']??null; + $OTPValidUntil = $oauthInfo['OTPValidUntil']??null; + + if(!$accessToken || !$refreshToken || !$accessTokenValidUntil || !$refreshTokenValidUntil){ + return [false, 'OAuth 정보가 보관되어 있지 않습니다. 카카오 로그인을 수행해 주세요.']; + } + + $now = TimeUtil::DatetimeNow(); + + if($now > $refreshTokenValidUntil){ + return [false, '로그인 토큰이 만료되었습니다. 카카오 로그인을 수행해 주세요.']; + } + + if($now > $accessTokenValidUntil){ + $apiHelper = new Kakao_REST_API_Helper($accessToken); + $refreshResult = $apiHelper->refresh_access_token($refreshToken); + if(!$refreshResult){ + return [false, '로그인 토큰 자동 갱신을 실패했습니다. 카카오 로그인을 수행해 주세요.']; + } + + $accessToken = $refreshResult['access_token']; + $accessTokenValidUntil = TimeUtil::DatetimeFromNowSecond($refreshResult['expires_in']); + + $oauthInfo['accessToken'] = $accessToken; + $oauthInfo['accessTokenValidUntil'] = $accessTokenValidUntil; + + $refreshToken = $refreshResult['refresh_token']??null; + if($refreshToken){ + $refreshTokenValidUntil = TimeUtil::DatetimeFromNowSecond($refreshResult['refresh_token_expires_in']); + + $oauthInfo['refreshToken'] = $refreshToken; + $oauthInfo['refresh_token_expires_in'] = $refresh_token_expires_in; + } + + RootDB::db()->update('member', [ + 'oauth_info'=>Json::encode($oauthInfo) + ], 'no=%i', $userInfo['no']); + } + + if($OTPValidUntil && $now <= $OTPValidUntil){ + return null; + } + + //인증 시스템 가동 + $session->access_token = $accessToken; + $session->expires = $accessTokenValidUntil; + $session->refresh_token = $refreshToken; + $session->refresh_token_expires = $refreshTokenValidUntil; + + if(!createOTPbyUserNO($userInfo['no'])){ + return [false, '인증 코드를 보내는데 실패했습니다.']; + } + + return [true, '인증 코드를 입력해주세요']; +} + $userInfo = $RootDB->queryFirstRow( - 'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl` '. + 'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl`, oauth_id, oauth_type, oauth_info '. 'from member where id=%s_username AND '. 'pw=sha2(concat(salt, %s_password, salt), 512)',[ 'username'=>$username, @@ -31,6 +107,7 @@ $userInfo = $RootDB->queryFirstRow( if(!$userInfo){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'아이디나 비밀번호가 올바르지 않습니다.' ]); } @@ -49,12 +126,14 @@ if($userInfo['delete_after']){ $RootDB->delete('member', 'no=%i', $userInfo['no']); Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요." ]); } else{ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>"삭제 요청된 계정입니다.[{$userInfo['delete_after']}]" ]); } @@ -70,10 +149,23 @@ $RootDB->insert('member_log',[ ]) ]); +if($userInfo['oauth_type'] == 'KAKAO'){ + $oauthFailResult = kakaoOAuthCheck($userInfo); + if($oauthFailResult !== null){ + $session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, Json::decode($userInfo['acl']??'{}')); + [$oauthReqOTP, $oauthFailReason] = $oauthFailResult; + Json::die([ + 'result'=>false, + 'reqOTP'=>$oauthReqOTP, + 'reason'=>$oauthFailReason + ]); + } +} -$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], Json::decode($userInfo['acl']??'{}')); +$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, Json::decode($userInfo['acl']??'{}')); Json::die([ 'result'=>true, + 'reqOTP'=>false, 'reason'=>'로그인 되었습니다.' ]); \ No newline at end of file diff --git a/js/join.js b/js/join.js index cd204ab6..a7a9ae0a 100644 --- a/js/join.js +++ b/js/join.js @@ -111,7 +111,7 @@ $(document).ready( function () { alert(obj.reason); } else{ - alert('정상적으로 가입되었습니다.'); + alert('회원 등록되었습니다. 첫 로그인 과정에서 인증 코드를 입력하는 것으로 계정이 활성화됩니다.'); } window.location.href = "../"; diff --git a/js/login.js b/js/login.js index f5c7ed10..02f4a9a2 100644 --- a/js/login.js +++ b/js/login.js @@ -48,14 +48,43 @@ $(document).ready( function () { 'password':hash_pw } }).then(function(obj){ - if(!obj.result){ + if(obj.result){ + window.location.href = "./"; + return; + } + if(!obj.reqOTP){ alert(obj.reason); + return; } - else{ - window.location.href = 'i_entrance/entrance.php'; - } + $('#modalOTP').modal().on('shown.bs.modal', function(){ + $('#otp_code').focus(); + }); + }); return false; }); + + $('#otp_form').submit(function(){ + $.post({ + url:'oauth_kakao/j_check_OTP.php', + dataType:'json', + data:{ + 'otp':$('#otp_code').val(), + } + }).then(function(obj){ + if(obj.result){ + window.location.href = "./"; + return; + } + + alert(obj.reason); + + if(obj.reset){ + $('#modalOTP').modal('hide') + return; + } + }); + return false; + }) } ); \ No newline at end of file diff --git a/oauth_kakao/j_change_pw.php b/oauth_kakao/j_change_pw.php index aa950fd8..1f621042 100644 --- a/oauth_kakao/j_change_pw.php +++ b/oauth_kakao/j_change_pw.php @@ -39,7 +39,7 @@ if($expires < $nowDate){ $email = null; $result = $restAPI->refresh_access_token($refresh_token); - if(!isset($refresh_token)){ + if(!isset($result)){ Json::die([ 'result'=>false, 'reason'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다' diff --git a/oauth_kakao/j_check_OTP.php b/oauth_kakao/j_check_OTP.php new file mode 100644 index 00000000..66d8c7b0 --- /dev/null +++ b/oauth_kakao/j_check_OTP.php @@ -0,0 +1,92 @@ +isLoggedIn()){ + Json::die([ + 'result'=>false, + 'reset'=>true, + 'reason'=>'이미 로그인 되어있습니다.' + ]); +} + +if(!$session->isLoggedIn(true)){ + Json::die([ + 'result'=>false, + 'reset'=>true, + 'reason'=>'인증 코드를 입력할 수 있는 상태가 아닙니다.' + ]); +} + +$otp = Util::getReq('otp', 'int'); +if(!$otp){ + Json::die([ + 'result'=>false, + 'reset'=>false, + 'reason'=>'인증 코드가 입력되지 않았습니다.' + ]); +} + +$userNo = $session->getUserID(); + +$oauthInfo = Json::decode(RootDB::db()->queryFirstField('SELECT oauth_info FROM member WHERE no=%i', $userNo))??[]; +if(!$oauthInfo){ + $session->logout(); + Json::die([ + 'result'=>false, + 'reset'=>true, + 'reason'=>'계정이 정상적으로 등록되어있지 않습니다.' + ]); +} + + +$OTPValue = $oauthInfo['OTPValue']??null; +$OTPTrialUntil = $oauthInfo['OTPTrialUntil']??null; +$OTPTrialCount = $oauthInfo['OTPTrialCount']??0; +$now = TimeUtil::DatetimeNow(); + +if(!$OTPTrialUntil || $OTPTrialUntil <= $now){ + $session->logout(); + Json::die([ + 'result'=>false, + 'reset'=>true, + 'reason'=>'인증 기한이 만료되었습니다. 다시 로그인해주세요.' + ]); +} + +if($OTPTrialCount <= 0){ + Json::die([ + 'result'=>false, + 'reset'=>false, + 'reason'=>"인증 실패 횟수를 초과했습니다. {$OTPTrialUntil}까지 기다려주세요." + ]); +} + +if($OTPValue != $otp){ + $OTPTrialCount -= 1; + $oauthInfo['OTPTrialCount'] = $OTPTrialCount; + RootDB::db()->update('member', [ + 'oauth_info'=>Json::encode($oauthInfo) + ], 'no=%i', $userNo); + Json::die([ + 'result'=>false, + 'reset'=>false, + 'reason'=>"인증 번호가 틀렸습니다. {$OTPTrialCount}회 더 시도할 수 있습니다." + ]); +} + +$OTPValidUntil = TimeUtil::DatetimeFromNowDay(10); +$session->setReqOTP(false); +$oauthInfo['OTPValidUntil'] = $OTPValidUntil; +RootDB::db()->update('member', [ + 'oauth_info'=>Json::encode($oauthInfo) +], 'no=%i', $userNo); + +Json::die([ + 'result'=>true, + 'reset'=>false, + 'reason'=>"로그인을 성공했습니다." +]); \ No newline at end of file diff --git a/oauth_kakao/j_join_process.php b/oauth_kakao/j_join_process.php index da51e1e7..04622e72 100644 --- a/oauth_kakao/j_join_process.php +++ b/oauth_kakao/j_join_process.php @@ -125,23 +125,28 @@ if(!$kakaoID && Util::array_get($signupResult['msg'])!='already registered'){ $me = $restAPI->meWithEmail(); $me['code'] = Util::array_get($me['code'], 0); +$kakao_account = $me['kakao_account']??[]; if ($me['code']< 0) { $restAPI->unlink(); Json::die([ 'result'=>false, - 'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.' + 'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.', ]); } -if(!Util::array_get($me['kaccount_email_verified'],false)){ +$validEmail = $kakao_account['is_email_valid']??false; +$verifiedEmail = $kakao_account['is_email_verified']??false; + +if(!$validEmail || !$verifiedEmail){ $restAPI->unlink(); Json::die([ 'result'=>false, - 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다' + 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다', + 'aux'=>$me ]); } -$email = $me['kaccount_email']; +$email = $kakao_account['email']??null; $session->kaccount_email = $email; $emailChk = checkEmailDup($email); if($emailChk !== true){ @@ -162,7 +167,13 @@ RootDB::db()->insert('member',[ 'pw' => $finalPassword, 'salt' => $userSalt, 'name'=>$nickname, - 'reg_date'=>$nowDate + 'reg_date'=>$nowDate, + 'oauth_info'=>Json::encode([ + 'accessToken'=>$access_token, + 'refreshToken'=>$refresh_token, + 'accessTokenValidUntil'=>$expires, + 'refreshTokenValidUntil'=>$refresh_token_expires + ]) ]); $userID = RootDB::db()->insertId(); diff --git a/oauth_kakao/j_login_oauth.php b/oauth_kakao/j_login_oauth.php index 343c6f6b..7d32e376 100644 --- a/oauth_kakao/j_login_oauth.php +++ b/oauth_kakao/j_login_oauth.php @@ -2,7 +2,7 @@ namespace sammo; require(__dir__.'/../vendor/autoload.php'); - +require('lib.join.php'); use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper; $RootDB = RootDB::db(); @@ -15,12 +15,13 @@ $canLogin = RootDB::db()->queryFirstField('SELECT `LOGIN` FROM `system` WHERE `N if($canLogin != 'Y'){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'현재는 로그인이 금지되어있습니다!', 'noRetry'=>true ]); } -$nowDate = TimeUtil::DatetimeNow(); +$now = TimeUtil::DatetimeNow(); $access_token = $session->access_token; $expires = $session->expires; @@ -32,6 +33,7 @@ $email = $session->kaccount_email; if(!$access_token || !$expires){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'카카오로그인이 이루어지지 않았습니다.' ]); } @@ -39,14 +41,15 @@ if(!$access_token || !$expires){ //TODO: join과 login의 동작이 비슷하다. helper class로 묶자. $restAPI = new Kakao_REST_API_Helper($access_token); -if($expires < $nowDate && (!$refresh_token || ($refresh_token_expires < $nowDate))){ +if($expires < $now && (!$refresh_token || ($refresh_token_expires < $now))){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'로그인 토큰 만료.'.$refresh_token_expires.' 다시 카카오로그인을 수행해주세요.' ]); } -if($expires < $nowDate){ +if($expires < $now){ $session->kaccount_email = null; $email = null; @@ -54,6 +57,7 @@ if($expires < $nowDate){ if(!isset($refresh_token)){ Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다' ]); } @@ -73,43 +77,69 @@ if(!$email){ if ($me['code']< 0) { Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.' ]); } - if(!Util::array_get($me['kaccount_email_verified'],false)){ + $kakao_account = $me['kakao_account']??null; + if (!$kakao_account) { + Json::die([ + 'result'=>false, + 'reqOTP'=>false, + 'reason'=>'카카오 로그인 정보를 제대로 받아오지 못했습니다.' + ]); + } + + if(!($kakao_account['has_email']??false)){ + Json::die([ + 'result'=>false, + 'reqOTP'=>false, + 'reason'=>'이메일 정보 공유를 허락해 주셔야 합니다.', + 'aux'=>$me + ]); + } + + $validEmail = $kakao_account['is_email_valid']??false; + $verifiedEmail = $kakao_account['is_email_verified']??false; + + if(!$validEmail || !$verifiedEmail){ $restAPI->unlink(); Json::die([ 'result'=>false, - 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다' + 'reqOTP'=>false, + 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다', ]); } - $email = $me['kaccount_email']; + $email = $kakao_account['email']; $session->kaccount_email = $email; } $userInfo = $RootDB->queryFirstRow( - 'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl` from member where email=%s',$email); + 'SELECT `no`, `id`, `name`, `grade`, `delete_after`, `acl`, oauth_info from member where email=%s',$email); if(!$userInfo){ $restAPI->unlink(); $session->access_token = null; Json::die([ 'result'=>false, - 'reason'=>'카카오로그인에 해당하는 계정이 없습니다. 재 가입을 시도해주세요.' + 'reqOTP'=>false, + 'reason'=>'카카오로그인에 해당하는 계정이 없습니다. 재 가입을 시도해주세요.', + 'aux'=>$session->tmpx, ]); } if($userInfo['delete_after']){ - if($userInfo['delete_after'] < $nowDate){ + if($userInfo['delete_after'] < $now){ $restAPI->unlink(); $session->access_token = null; $RootDB->delete('member', 'no=%i', $userInfo['no']); Json::die([ 'result'=>false, - 'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요." + 'reqOTP'=>false, + 'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요.", ]); } else{ @@ -117,12 +147,43 @@ if($userInfo['delete_after']){ $session->access_token = null; Json::die([ 'result'=>false, + 'reqOTP'=>false, 'reason'=>"삭제 요청된 계정입니다.[{$userInfo['delete_after']}]" ]); } } +$oauthInfo = Json::decode($userInfo['oauth_info'])??[]; +$oauthInfo['accessToken'] = $access_token; +$oauthInfo['refreshToken'] = $refresh_token; +$oauthInfo['accessTokenValidUntil'] = $expires; +$oauthInfo['refreshTokenValidUntil'] = $refresh_token_expires; + +RootDB::db()->update('member', [ + 'oauth_info'=>Json::encode($oauthInfo) +], 'no=%i', $userInfo['no']); + + +$OTPValidUntil = $oauthInfo['OTPValidUntil']??null; + +if(!$OTPValidUntil || $OTPValidUntil < $now){ + if(!createOTPbyUserNO($userInfo['no'])){ + Json::die([ + 'result'=>false, + 'reqOTP'=>false, + 'reason'=>'인증 코드를 보내는데 실패했습니다.' + ]); + } + $session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], true, Json::decode($userInfo['acl']??'{}')); + Json::die([ + 'result'=>false, + 'reqOTP'=>true, + 'reason'=>'인증 코드를 입력해주세요.' + ]); +} + + $RootDB->insert('member_log',[ 'member_no'=>$userInfo['no'], 'action_type'=>'login', @@ -132,8 +193,9 @@ $RootDB->insert('member_log',[ ]) ]); -$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], Json::decode($userInfo['acl']??'{}')); +$session->login($userInfo['no'], $userInfo['id'], $userInfo['grade'], false, Json::decode($userInfo['acl']??'{}')); Json::die([ 'result'=>true, + 'reqOTP'=>false, 'reason'=>'로그인 되었습니다.' ]); \ No newline at end of file diff --git a/oauth_kakao/lib.join.php b/oauth_kakao/lib.join.php index da840493..d0ac4e82 100644 --- a/oauth_kakao/lib.join.php +++ b/oauth_kakao/lib.join.php @@ -1,5 +1,6 @@ delete('member', 'no=%i', $userInfo['no']); } return true; -} \ No newline at end of file +} + +function createOTPbyUserNO(int $userNo):bool{ + $userInfo = RootDB::db()->queryFirstRow('SELECT oauth_info FROM member WHERE no=%i', $userNo); + if(!$userInfo){ + return false; + } + + $oauthInfo = Json::decode($userInfo['oauth_info']); + if(!$oauthInfo){ + return false; + } + + $accessToken = $oauthInfo['accessToken']; + $OTPValue = $oauthInfo['OTPValue']??null; + $OTPTrialUntil = $oauthInfo['OTPTrialUntil']??null; + + $now = TimeUtil::DatetimeNow(); + + + if($OTPTrialUntil && $OTPValue && $OTPTrialUntil > $now){ + return true; + } + + [$OTPValue, $OTPTrialUntil] = createOTP($accessToken); + + if(!$OTPValue){ + return false; + } + + $oauthInfo['OTPValue'] = $OTPValue; + $oauthInfo['OTPTrialUntil'] = $OTPTrialUntil; + $oauthInfo['OTPTrialCount'] = 3; + + RootDB::db()->update('member', [ + 'oauth_info'=>Json::encode($oauthInfo) + ], 'no=%i', $userNo); + + return true; +} + +function createOTP(string $accessToken):array{ + $restAPI = new Kakao_REST_API_Helper($accessToken); + + $OTPValue = Util::randRangeInt(10000, 99999); + $OTPTrialUntil = TimeUtil::DatetimeFromNowSecond(180); + + $sendResult = $restAPI->talk_to_me_default([ + "object_type"=> "text", + "text"=> "인증 코드는 $OTPValue 입니다. $OTPTrialUntil 이내에 입력해주세요.", + "link"=> [ + "web_url"=> ServConfig::getServerBasepath(), + "mobile_web_url" => ServConfig::getServerBasepath() + ], + "button_title"=> "로그인 페이지 열기" + ]); + $sendResult['code'] = Util::array_get($sendResult['code'], 0); + if($sendResult['code'] < 0){ + return null; + } + + return [$OTPValue, $OTPTrialUntil]; +} + diff --git a/oauth_kakao/oauth.php b/oauth_kakao/oauth.php index 4a9017e8..f6e0b856 100644 --- a/oauth_kakao/oauth.php +++ b/oauth_kakao/oauth.php @@ -47,7 +47,12 @@ $me = $restAPI->meWithEmail(); $oauth_mode = 'login'; $me['code'] = Util::array_get($me['code'], 0); -if($me['code']< 0){ +$signed = $me['has_signed_up']??false; +$kakao_account = $me['kakao_account']??[]; +if(!$signed){ + $oauth_mode = 'join'; +} +else if($me['code']< 0){ switch(Util::array_get($me['msg'])){ case 'NotRegisteredUserException': $oauth_mode = 'join'; @@ -57,7 +62,7 @@ if($me['code']< 0){ } } else{ - $session->kaccount_email = $me['kaccount_email']; + $session->kaccount_email = $$kakao_account['email']; } ?> diff --git a/src/kakao/Kakao_REST_API_Helper.php b/src/kakao/Kakao_REST_API_Helper.php index 7e568cc9..882d8168 100644 --- a/src/kakao/Kakao_REST_API_Helper.php +++ b/src/kakao/Kakao_REST_API_Helper.php @@ -25,7 +25,7 @@ class User_Management_Path public static $SIGNUP = "/v1/user/signup"; public static $UNLINK = "/v1/user/unlink"; public static $LOGOUT = "/v1/user/logout"; - public static $ME = "/v1/user/me"; + public static $ME = "/v2/user/me"; public static $UPDATE_PROFILE = "/v1/user/update_profile"; public static $USER_IDS = "/v1/user/ids"; } @@ -97,12 +97,12 @@ class Kakao_REST_API_Helper $requestUrl .= '?'.$params; } - $opts = array( - CURLOPT_URL => $requestUrl, - CURLOPT_RETURNTRANSFER => true, - CURLOPT_SSL_VERIFYPEER => false, - CURLOPT_SSLVERSION => 1, - ); + $opts = [ + CURLOPT_URL => $requestUrl, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => false, + CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1, + ]; if ($api_path != '/oauth/token') { if (in_array($api_path, self::$admin_apis)) { @@ -213,8 +213,12 @@ class Kakao_REST_API_Helper public function meWithEmail() { $params = [ - 'propertyKeys'=>'["id","kaacount_email","kaccount_email_verified"]' - ]; + 'property_keys'=>'['. + '"id",'. + '"kakao_account.has_email","kakao_account.email",'. + '"kakao_account.is_email_valid","kakao_account.is_email_verified"'. + ']' + ]; return $this->request(User_Management_Path::$ME); } diff --git a/src/sammo/Session.php b/src/sammo/Session.php index c25c5a34..f3f0ced6 100644 --- a/src/sammo/Session.php +++ b/src/sammo/Session.php @@ -8,12 +8,14 @@ namespace sammo; * @property string $userName 유저명 * @property int $userGrade 유저등급 * @property string $ip IP + * @property bool $reqOTP 인증 코드 필요 * @property array $acl 권한 */ class Session { const PROTECTED_NAMES = [ 'ip'=>true, + 'reqOTP'=>true, 'time'=>true, 'userID'=>true, 'userName'=>true, @@ -163,7 +165,7 @@ class Session return Util::array_get($_SESSION[$name]); } - public function login(int $userID, string $userName, int $grade, array $acl): Session + public function login(int $userID, string $userName, int $grade, bool $reqOTP, array $acl): Session { $this->set('userID', $userID); $this->set('userName', $userName); @@ -171,10 +173,15 @@ class Session $this->set('time', time()); $this->set('userGrade', $grade); $this->set('acl', $acl); + $this->set('reqOTP', $reqOTP); $this->set('access_token', null); return $this; } + public function setReqOTP(bool $reqOTP=false){ + $this->set('reqOTP', $reqOTP); + } + public function logout(): Session { @@ -189,6 +196,7 @@ class Session $this->set('userName', null); $this->set('userGrade', null); $this->set('acl', null); + $this->set('reqOTP', null); $this->set('time', time()); return $this; } @@ -324,9 +332,12 @@ class Session return $obj->userID; } - public function isLoggedIn(): bool + public function isLoggedIn(bool $ignoreOTP = false): bool { - if ($this->userID) { + if (!$ignoreOTP && $this->reqOTP){ + return false; + } + else if ($this->userID) { return true; } else { return false; From bd25de930b4e77d3f751c0aa82da9a178d233c62 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 9 Sep 2018 20:22:34 +0900 Subject: [PATCH 3/7] =?UTF-8?q?=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=EC=9A=A9=20=EB=94=94=EB=B2=84=EA=B9=85=20?= =?UTF-8?q?=EC=BD=94=EB=93=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- oauth_kakao/j_join_process.php | 1 - oauth_kakao/j_login_oauth.php | 1 - 2 files changed, 2 deletions(-) diff --git a/oauth_kakao/j_join_process.php b/oauth_kakao/j_join_process.php index 04622e72..940b721b 100644 --- a/oauth_kakao/j_join_process.php +++ b/oauth_kakao/j_join_process.php @@ -142,7 +142,6 @@ if(!$validEmail || !$verifiedEmail){ Json::die([ 'result'=>false, 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다', - 'aux'=>$me ]); } diff --git a/oauth_kakao/j_login_oauth.php b/oauth_kakao/j_login_oauth.php index 7d32e376..8056358a 100644 --- a/oauth_kakao/j_login_oauth.php +++ b/oauth_kakao/j_login_oauth.php @@ -96,7 +96,6 @@ if(!$email){ 'result'=>false, 'reqOTP'=>false, 'reason'=>'이메일 정보 공유를 허락해 주셔야 합니다.', - 'aux'=>$me ]); } From 7b3ef45300aadeea5b59170222b444ae7196a2c6 Mon Sep 17 00:00:00 2001 From: hide_d Date: Sun, 9 Sep 2018 21:16:44 +0900 Subject: [PATCH 4/7] =?UTF-8?q?=EC=B9=B4=EC=B9=B4=EC=98=A4=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=EC=9E=91=EC=97=85=20=EA=B0=9C=EC=84=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- index.php | 17 +++++++++++------ js/join.js | 2 +- js/login.js | 1 + oauth_kakao/index.php | 3 +++ oauth_kakao/j_check_OTP.php | 2 +- oauth_kakao/j_join_process.php | 8 ++++++++ oauth_kakao/j_login_oauth.php | 2 +- oauth_kakao/oauth.php | 7 +++++-- oauth_kakao/oauth_fail.html | 2 +- 9 files changed, 32 insertions(+), 12 deletions(-) diff --git a/index.php b/index.php index d3ddb6bd..ed2d54fa 100644 --- a/index.php +++ b/index.php @@ -100,6 +100,9 @@ function postOAuthResult(result){ if(result == 'join'){ window.location.href = 'oauth_kakao/join.php'; } + else if(result == 'req_email'){ + alert('이메일 정보 공유를 허가해 주셔야 합니다.'); + } else if(result == 'login'){ console.log('로그인모드'); if(oauthMode=='change_pw'){ @@ -194,14 +197,16 @@ function postOAuthResult(result){