카카오 로그인 초기 구현
This commit is contained in:
@@ -98,6 +98,10 @@ input::-webkit-input-placeholder {
|
||||
z-index:800;
|
||||
}
|
||||
|
||||
#login_card{
|
||||
z-index:801;
|
||||
}
|
||||
|
||||
#btn_kakao_login{
|
||||
cursor: pointer;
|
||||
height:46px;
|
||||
|
||||
@@ -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){
|
||||
<h1 class="row justify-content-md-center">삼국지 모의전투 HiDCHe</h1>
|
||||
<div class="row justify-content-md-center">
|
||||
<div class="col" style="max-width:450px;">
|
||||
<div class="card">
|
||||
<div class="card" id="login_card">
|
||||
<h3 class="card-header">
|
||||
로그인
|
||||
</h3>
|
||||
@@ -152,7 +158,7 @@ function postOAuthResult(result){
|
||||
|
||||
<input type="hidden" id="global_salt" name="global_salt" value="<?=RootDB::getGlobalSalt()?>">
|
||||
<div class="form-group row">
|
||||
<div class="col-5 col-md-4 " style="position:relative;"><button type="button" onclick="getOAuthToken('login');" id="btn_kakao_login" title="카카오톡으로 가입&로그인"></button></div>
|
||||
<div class="col-5 col-md-4 " style="position:relative;"><button type="button" onclick="getOAuthToken('login', ['account_email','talk_message']);" id="btn_kakao_login" title="카카오톡으로 가입&로그인"></button></div>
|
||||
<div class="col-7 col-md-8">
|
||||
<button type="submit" class="btn btn-primary btn-lg btn-block login-button">로그인</button>
|
||||
</div>
|
||||
@@ -172,9 +178,40 @@ function postOAuthResult(result){
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="bottom_box">
|
||||
<div class="container"><a href="terms.2.html">개인정보처리방침</a> & <a href="terms.1.html">이용약관</a><br>© 2018 • HideD
|
||||
<br>크롬과 파이어폭스에 최적화되어있습니다.</div></div>
|
||||
</div>
|
||||
|
||||
<div class="modal fade" id="modalOTP" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<form id="otp_form" method="post" action="#">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title" id="exampleModalLabel">인증 코드 필요</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<div class="form-group row">
|
||||
인증 코드가 필요합니다. 카카오톡의 '나와의 채팅'란을 확인해 주세요.<br>
|
||||
</div>
|
||||
<div class="form-group row">
|
||||
<label for="otp" class="col-5 col-md-4 col-form-label">인증 코드</label>
|
||||
<div class="col-7 col-md-8">
|
||||
<input autocomplete="off" type="number" class="form-control" name='otp' id="otp_code" autofocus="autofocus" placeholder="인증 코드">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-secondary" data-dismiss="modal">취소</button>
|
||||
<button type="submit" class="btn btn-primary">제출</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
+94
-2
@@ -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'=>'로그인 되었습니다.'
|
||||
]);
|
||||
+1
-1
@@ -111,7 +111,7 @@ $(document).ready( function () {
|
||||
alert(obj.reason);
|
||||
}
|
||||
else{
|
||||
alert('정상적으로 가입되었습니다.');
|
||||
alert('회원 등록되었습니다. 첫 로그인 과정에서 인증 코드를 입력하는 것으로 계정이 활성화됩니다.');
|
||||
}
|
||||
|
||||
window.location.href = "../";
|
||||
|
||||
+33
-4
@@ -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;
|
||||
})
|
||||
} );
|
||||
@@ -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'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다'
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
|
||||
require(__dir__.'/../vendor/autoload.php');
|
||||
|
||||
$RootDB = RootDB::db();
|
||||
$session = Session::getInstance();
|
||||
if($session->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'=>"로그인을 성공했습니다."
|
||||
]);
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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'=>'로그인 되었습니다.'
|
||||
]);
|
||||
@@ -1,5 +1,6 @@
|
||||
<?php
|
||||
namespace sammo;
|
||||
use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper;
|
||||
|
||||
function checkUsernameDup($username){
|
||||
if(!$username){
|
||||
@@ -62,4 +63,67 @@ function checkEmailDup($email){
|
||||
RootDB::db()->delete('member', 'no=%i', $userInfo['no']);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
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];
|
||||
}
|
||||
|
||||
|
||||
@@ -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'];
|
||||
}
|
||||
|
||||
?>
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
+14
-3
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user