Compare commits

...
8 Commits
21 changed files with 628 additions and 88 deletions
+6 -2
View File
@@ -52,8 +52,8 @@ input::-webkit-input-placeholder {
} }
.login-button{ .login_btn_group{
margin-top: 5px; margin-top: 5px;
} }
.login-register{ .login-register{
@@ -98,6 +98,10 @@ input::-webkit-input-placeholder {
z-index:800; z-index:800;
} }
#login_card{
z-index:801;
}
#btn_kakao_login{ #btn_kakao_login{
cursor: pointer; cursor: pointer;
height:46px; height:46px;
+4 -2
View File
@@ -20,16 +20,18 @@ ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
CREATE TABLE `member` ( CREATE TABLE `member` (
`NO` INT(11) NOT NULL AUTO_INCREMENT, `NO` INT(11) NOT NULL AUTO_INCREMENT,
`oauth_id` BIGINT(20) NULL DEFAULT NULL, `oauth_id` BIGINT(20) NULL DEFAULT NULL,
`oauth_type` ENUM('NONE','KAKAO') NOT NULL,
`ID` VARCHAR(64) NOT NULL, `ID` VARCHAR(64) NOT NULL,
`EMAIL` VARCHAR(64) NULL DEFAULT NULL, `EMAIL` VARCHAR(64) NULL DEFAULT NULL,
`oauth_type` ENUM('NONE','KAKAO') NOT NULL,
`oauth_info` TEXT NOT NULL DEFAULT '{}',
`token_valid_until` DATETIME NULL DEFAULT NULL,
`PW` CHAR(128) NOT NULL, `PW` CHAR(128) NOT NULL,
`salt` CHAR(16) NOT NULL, `salt` CHAR(16) NOT NULL,
`third_use` INT(1) NOT NULL DEFAULT '0', `third_use` INT(1) NOT NULL DEFAULT '0',
`NAME` VARCHAR(64) NOT NULL, `NAME` VARCHAR(64) NOT NULL,
`PICTURE` VARCHAR(64) NULL DEFAULT 'default.jpg', `PICTURE` VARCHAR(64) NULL DEFAULT 'default.jpg',
`IMGSVR` INT(1) NULL DEFAULT '0', `IMGSVR` INT(1) NULL DEFAULT '0',
`acl` text NOT NULL DEFAULT '{}' COMMENT 'json', `acl` TEXT NOT NULL DEFAULT '{}' COMMENT 'json',
`GRADE` INT(1) NULL DEFAULT '1', `GRADE` INT(1) NULL DEFAULT '1',
`REG_NUM` INT(3) NULL DEFAULT '0', `REG_NUM` INT(3) NULL DEFAULT '0',
`REG_DATE` DATETIME NOT NULL, `REG_DATE` DATETIME NOT NULL,
+1 -1
View File
@@ -784,7 +784,7 @@ class WarUnitGeneral extends WarUnit{
foreach($table as $skillKey => $skillMultiply){ foreach($table as $skillKey => $skillMultiply){
if($oppose->hasActivatedSkill($skillKey)){ if($oppose->hasActivatedSkill($skillKey)){
$josaUl = \sammo\JosaUtil::pick($skillKey, '을'); $josaUl = \sammo\JosaUtil::pick($skillKey, '을');
$thisLogger->pushGeneralBattleDetailLog("<C>●</><C>반계</>로 상대의 <D>{$skillKey}</>{$josaUl} 되돌렸다!"); $thisLogger->pushGeneralBattleDetailLog("<C>반계</>로 상대의 <D>{$skillKey}</>{$josaUl} 되돌렸다!");
$opposeLogger->pushGeneralBattleDetailLog("<D>{$skillKey}</>{$josaUl} <R>역으로</> 당했다!"); $opposeLogger->pushGeneralBattleDetailLog("<D>{$skillKey}</>{$josaUl} <R>역으로</> 당했다!");
$this->multiplyWarPowerMultiply($skillMultiply); $this->multiplyWarPowerMultiply($skillMultiply);
+7 -2
View File
@@ -9,7 +9,7 @@ $userID = Session::getUserID();
// 외부 파라미터 // 외부 파라미터
$db = RootDB::db(); $db = RootDB::db();
$member = $db->queryFirstRow('SELECT `id`, `name`, `grade`, `picture`, reg_date, third_use, acl FROM `member` WHERE `NO` = %i', $userID); $member = $db->queryFirstRow('SELECT `id`, `name`, `grade`, `picture`, reg_date, third_use, acl, oauth_type, token_valid_until FROM `member` WHERE `NO` = %i', $userID);
if(!$member['picture']){ if(!$member['picture']){
$picture = ServConfig::getSharedIconPath().'/default.jpg'; $picture = ServConfig::getSharedIconPath().'/default.jpg';
@@ -30,6 +30,8 @@ else{
} }
} }
$tokenValidUntil = $member['token_valid_until'];
if($member['grade'] == 6) { if($member['grade'] == 6) {
$grade = '운영자'; $grade = '운영자';
} elseif($member['grade'] == 5) { } elseif($member['grade'] == 5) {
@@ -81,5 +83,8 @@ Json::die([
'global_salt'=>RootDB::getGlobalSalt(), 'global_salt'=>RootDB::getGlobalSalt(),
'join_date'=>$member['reg_date'], 'join_date'=>$member['reg_date'],
'third_use'=>($member['third_use']!=0), 'third_use'=>($member['third_use']!=0),
'acl'=>$acl 'acl'=>$acl,
'oauth_type'=>$member['oauth_type'],
'token_valid_until'=>$tokenValidUntil
]); ]);
+9
View File
@@ -23,6 +23,7 @@ require(__dir__.'/../vendor/autoload.php');
<?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?> <?=WebUtil::printJS('../e_lib/jquery-3.3.1.min.js')?>
<?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?> <?=WebUtil::printJS('../e_lib/bootstrap.bundle.min.js')?>
<?=WebUtil::printJS('../e_lib/sha512.min.js')?> <?=WebUtil::printJS('../e_lib/sha512.min.js')?>
<?=WebUtil::printJS('../e_lib/moment.min.js')?>
<?=WebUtil::printJS('../js/func.js')?> <?=WebUtil::printJS('../js/func.js')?>
<?=WebUtil::printJS('../js/user_info.js')?> <?=WebUtil::printJS('../js/user_info.js')?>
<?=WebUtil::printJS('../d_shared/menu.js')?> <?=WebUtil::printJS('../d_shared/menu.js')?>
@@ -87,6 +88,14 @@ require(__dir__.'/../vendor/autoload.php');
</td> </td>
<td colspan="3">개인정보 3자 제공 동의 : <span id="slot_third_use"></span><button type="button" id="third_use_disallow">철회</button></td> <td colspan="3">개인정보 3자 제공 동의 : <span id="slot_third_use"></span><button type="button" id="third_use_disallow">철회</button></td>
</tr> </tr>
<tr>
<th class="bg1">인증 방식</th>
<td colspan="2">
<span id="slot_oauth_type"></span>
</td>
<td colspan="3">
<span id="slot_token_valid_until"></span>까지 유효<button type="button" id="expand_login_token">초기화</button></td>
</tr>
<tr> <tr>
<th class="bg1"></th> <th class="bg1"></th>
<th class="bg1" colspan="2">회원 탈퇴</th> <th class="bg1" colspan="2">회원 탈퇴</th>
+68 -9
View File
@@ -64,8 +64,17 @@ function getOAuthToken(mode, scope_list){
function sendTempPasswordToKakaoTalk(){ function sendTempPasswordToKakaoTalk(){
$.post({ $.post({
url:'j_change_pw.php', url:'oauth_kakao/j_login_oauth.php',
dataType:'json' dataType:'json'
}).then(function(obj){
var t = $.Deferred();
if(!obj.result){
t.reject();
}
return $.post({
url:'oauth_kakao/j_change_pw.php',
dataType:'json'
});
}).then(function(obj){ }).then(function(obj){
if(!obj.result){ if(!obj.result){
alert(obj.reason); alert(obj.reason);
@@ -81,12 +90,18 @@ function doLoginUsingOAuth(){
url:'oauth_kakao/j_login_oauth.php', url:'oauth_kakao/j_login_oauth.php',
dataType:'json' dataType:'json'
}).then(function(obj){ }).then(function(obj){
if(!obj.result){ if(obj.result){
alert(obj.reason);
}
else{
window.location.href = "./"; window.location.href = "./";
return;
} }
if(!obj.reqOTP){
alert(obj.reason);
return;
}
$('#modalOTP').modal().on('shown.bs.modal', function(){
$('#otp_code').focus();
});
}); });
} }
@@ -94,6 +109,9 @@ function postOAuthResult(result){
if(result == 'join'){ if(result == 'join'){
window.location.href = 'oauth_kakao/join.php'; window.location.href = 'oauth_kakao/join.php';
} }
else if(result == 'req_email'){
alert('이메일 정보 공유를 허가해 주셔야 합니다.');
}
else if(result == 'login'){ else if(result == 'login'){
console.log('로그인모드'); console.log('로그인모드');
if(oauthMode=='change_pw'){ if(oauthMode=='change_pw'){
@@ -126,7 +144,7 @@ function postOAuthResult(result){
<h1 class="row justify-content-md-center">삼국지 모의전투 HiDCHe</h1> <h1 class="row justify-content-md-center">삼국지 모의전투 HiDCHe</h1>
<div class="row justify-content-md-center"> <div class="row justify-content-md-center">
<div class="col" style="max-width:450px;"> <div class="col" style="max-width:450px;">
<div class="card"> <div class="card" id="login_card">
<h3 class="card-header"> <h3 class="card-header">
로그인 로그인
</h3> </h3>
@@ -152,9 +170,17 @@ function postOAuthResult(result){
<input type="hidden" id="global_salt" name="global_salt" value="<?=RootDB::getGlobalSalt()?>"> <input type="hidden" id="global_salt" name="global_salt" value="<?=RootDB::getGlobalSalt()?>">
<div class="form-group row"> <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="카카오톡으로 가입&amp;로그인"></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="카카오톡으로 가입&amp;로그인"></button></div>
<div class="col-7 col-md-8"> <div class="col-7 col-md-8">
<button type="submit" class="btn btn-primary btn-lg btn-block login-button">로그인</button> <div class="btn-group btn-group-lg d-flex login_btn_group" role="group">
<button type="submit" class="btn btn-primary login-button w-100">로그인</button>
<div class="btn-group" role="group">
<button type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> </button>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="btnGroupDrop1">
<a class="dropdown-item" href="javascript:getOAuthToken('change_pw', 'talk_message');">비밀번호 초기화</a>
</div>
</div>
</div>
</div> </div>
</div> </div>
</form> </form>
@@ -172,9 +198,42 @@ function postOAuthResult(result){
</div> </div>
</div> </div>
</div> </div>
</div>
<div id="bottom_box"> <div id="bottom_box">
<div class="container"><a href="terms.2.html">개인정보처리방침</a> &amp; <a href="terms.1.html">이용약관</a><br>© 2018 • HideD <div class="container"><a href="terms.2.html">개인정보처리방침</a> &amp; <a href="terms.1.html">이용약관</a><br>© 2018 • HideD
<br>크롬과 파이어폭스에 최적화되어있습니다.</div></div> <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">&times;</span>
</button>
</div>
<div class="modal-body">
<div>
인증 코드가 필요합니다.<br><br>
카카오톡의 '나와의 채팅'란을 확인해 주세요.<br>
(별도의 알림[소리, 진동, 숫자]이 발생하지 않습니다.)
</div>
<div class="input-group mt-4" role="group">
<div class="input-group-prepend">
<span class="input-group-text">인증 코드</span>
</div>
<input type="number" class="form-control" name='otp' id="otp_code" placeholder="인증 코드">
</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> </body>
</html> </html>
+94 -2
View File
@@ -2,7 +2,9 @@
namespace sammo; namespace sammo;
require(__dir__.'/vendor/autoload.php'); 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(); $RootDB = RootDB::db();
$session = Session::getInstance(); $session = Session::getInstance();
@@ -16,12 +18,86 @@ $password = Util::getReq('password');
if(!$username || !$password){ if(!$username || !$password){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'올바르지 않은 입력입니다.' '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;
$tokenValidUntil = $member['token_valid_until'];
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($tokenValidUntil && $now <= $tokenValidUntil){
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( $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 '. 'from member where id=%s_username AND '.
'pw=sha2(concat(salt, %s_password, salt), 512)',[ 'pw=sha2(concat(salt, %s_password, salt), 512)',[
'username'=>$username, 'username'=>$username,
@@ -31,6 +107,7 @@ $userInfo = $RootDB->queryFirstRow(
if(!$userInfo){ if(!$userInfo){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'아이디나 비밀번호가 올바르지 않습니다.' 'reason'=>'아이디나 비밀번호가 올바르지 않습니다.'
]); ]);
} }
@@ -49,12 +126,14 @@ if($userInfo['delete_after']){
$RootDB->delete('member', 'no=%i', $userInfo['no']); $RootDB->delete('member', 'no=%i', $userInfo['no']);
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요." 'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요."
]); ]);
} }
else{ else{
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>"삭제 요청된 계정입니다.[{$userInfo['delete_after']}]" '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([ Json::die([
'result'=>true, 'result'=>true,
'reqOTP'=>false,
'reason'=>'로그인 되었습니다.' 'reason'=>'로그인 되었습니다.'
]); ]);
+1 -1
View File
@@ -111,7 +111,7 @@ $(document).ready( function () {
alert(obj.reason); alert(obj.reason);
} }
else{ else{
alert('정상적으로 가입되었습니다.'); alert('회원 등록되었습니다.\n첫 로그인 과정에서 인증 코드를 입력하는 것으로 계정이 활성화됩니다.');
} }
window.location.href = "../"; window.location.href = "../";
+34 -4
View File
@@ -48,14 +48,44 @@ $(document).ready( function () {
'password':hash_pw 'password':hash_pw
} }
}).then(function(obj){ }).then(function(obj){
if(!obj.result){ if(obj.result){
window.location.href = "./";
return;
}
if(!obj.reqOTP){
alert(obj.reason); alert(obj.reason);
return;
} }
else{ $('#modalOTP').modal().on('shown.bs.modal', function(){
window.location.href = 'i_entrance/entrance.php'; $('#otp_code').focus();
} });
}); });
return false; 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){
alert(obj.reason);
window.location.href = "./";
return;
}
alert(obj.reason);
if(obj.reset){
$('#modalOTP').modal('hide')
return;
}
});
return false;
})
} ); } );
+43
View File
@@ -20,6 +20,16 @@ function fillUserInfo(result){
if(result.third_use){ if(result.third_use){
$('#third_use_disallow').show(); $('#third_use_disallow').show();
} }
$('#slot_oauth_type').text(result.oauth_type);
if(result.oauth_type != 'NONE'){
$('#slot_token_valid_until').text(result.token_valid_until);
}
else{
$('#slot_token_valid_until').parent().html('');
}
} }
function changeIconPreview(){ function changeIconPreview(){
@@ -217,6 +227,37 @@ function deleteMe(){
}); });
} }
function extendAuth(){
var validUntil = $('#slot_token_valid_until').html();
var availableAt = moment(validUntil).subtract(5, 'days').format('YYYY-MM-DD HH:mm:ss');
var now = moment().format('YYYY-MM-DD HH:mm:ss');
if(now < availableAt){
alert('{0}부터 초기화할 수 있습니다.'.format(availableAt));
return false;
}
if(!confirm('로그아웃됩니다. 진행할까요?')){
return;
}
$.ajax({
type:'post',
url:'../oauth_kakao/j_reset_token.php',
dataType:'json',
}).then(function(result){
if(!result.result){
alert(result.reason);
}
else{
alert('초기화했습니다. 다시 로그인해 주십시오.');
location.href='../';
}
},function(){
alert('알 수 없는 이유로 로그인 토큰 연장에 실패했습니다.');
});
}
$(function(){ $(function(){
$('#slot_icon, #slot_new_icon').attr('src', pathConfig.sharedIcon+'/default.jpg'); $('#slot_icon, #slot_new_icon').attr('src', pathConfig.sharedIcon+'/default.jpg');
$.ajax({ $.ajax({
@@ -255,4 +296,6 @@ $(function(){
deleteMe(e); deleteMe(e);
} }
}); });
$('#expand_login_token').click(extendAuth);
}) })
+3
View File
@@ -64,6 +64,9 @@ function postOAuthResult(result){
if(result == 'join'){ if(result == 'join'){
window.location.href = 'join.php'; window.location.href = 'join.php';
} }
else if(result == 'req_email'){
alert('이메일 정보 공유를 허가해 주셔야 합니다.');
}
else if(result == 'login'){ else if(result == 'login'){
console.log('로그인모드'); console.log('로그인모드');
if(oauthMode=='change_pw'){ if(oauthMode=='change_pw'){
+23 -31
View File
@@ -5,7 +5,7 @@ require(__dir__.'/../vendor/autoload.php');
use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper; use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper;
$nowDate = TimeUtil::DatetimeNow(); $now = TimeUtil::DatetimeNow();
$session = Session::requireLogin([ $session = Session::requireLogin([
'reason'=>'로그인이 되어있지 않습니다' 'reason'=>'로그인이 되어있지 않습니다'
@@ -13,8 +13,6 @@ $session = Session::requireLogin([
$userID = Session::getUserID(); $userID = Session::getUserID();
$access_token = $session->access_token; $access_token = $session->access_token;
$expires = $session->expires; $expires = $session->expires;
$refresh_token = $session->refresh_token;
$refresh_token_expires = $session->refresh_token_expires;
if(!$access_token || !$expires){ if(!$access_token || !$expires){
Json::die([ Json::die([
@@ -27,44 +25,37 @@ if(!$access_token || !$expires){
//TODO: join과 login의 동작이 비슷하다. helper class로 묶자. //TODO: join과 login의 동작이 비슷하다. helper class로 묶자.
$restAPI = new Kakao_REST_API_Helper($access_token); $restAPI = new Kakao_REST_API_Helper($access_token);
if($expires < $nowDate && (!$refresh_token || ($refresh_token_expires < $nowDate))){ $session->logout();
if($expires < $now){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'로그인 토큰 만료.'.$refresh_token_expires.' 다시 카카오로그인을 수행해주세요.' 'reason'=>'로그인 토큰 만료. 카카오 로그인을 먼저 수행해주세요.'
]); ]);
} }
if($expires < $nowDate){
$session->kaccount_email = null;
$email = null;
$result = $restAPI->refresh_access_token($refresh_token);
if(!isset($refresh_token)){
Json::die([
'result'=>false,
'reason'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다'
]);
}
$access_token = $result['access_token'];
$expires = TimeUtil::DatetimeFromNowSecond($result['expires_in']);
if(isset($result['refresh_token'])){
$refresh_token = Util::array_get($result['refresh_token']);
$refresh_token_expires = TimeUtil::DatetimeFromNowSecond($result['refresh_token_expires_in']);
}
}
RootDB::db()->query("lock tables member write, member_log write"); RootDB::db()->query("lock tables member write, member_log write");
$isUser = RootDB::db()->queryFirstRow( $oauthInfo = Json::decode(RootDB::db()->queryFirstField('SELECT oauth_info from member where no=%i',$userID))??[];
'SELECT count(`no`) from member where no=%i',$userID); if(!$oauthInfo){
if(!$isUser){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'회원이 아닙니다. 관리자에게 문의해주세요.' 'reason'=>'제대로 로그인이 이루어져 있지 않습니다.'
]); ]);
} }
$nextPasswordChange = $oauthInfo['nextPasswordChange']??null;
if($nextPasswordChange && $now < $nextPasswordChange){
Json::die([
'result'=>false,
'reason'=>'비밀번호를 초기화한지 얼마 지나지 않았습니다.'
]);
}
$nextPasswordChange = TimeUtil::DatetimeFromNowHour(4);
$oauthInfo['nextPasswordChange'] = $nextPasswordChange;
$newPassword = Util::randomStr(6); $newPassword = Util::randomStr(6);
$tmpPassword = Util::hashPassword(RootDB::getGlobalSalt(), $newPassword); $tmpPassword = Util::hashPassword(RootDB::getGlobalSalt(), $newPassword);
$newSalt = bin2hex(random_bytes(8)); $newSalt = bin2hex(random_bytes(8));
@@ -89,12 +80,13 @@ if($sendResult['code'] < 0){
RootDB::db()->update('member', [ RootDB::db()->update('member', [
'pw'=>$newFinalPassword, 'pw'=>$newFinalPassword,
'salt'=>$newSalt 'salt'=>$newSalt,
'oauth_info'=>Json::encode($oauthInfo),
],'no=%i', $userID); ],'no=%i', $userID);
RootDB::db()->insert('member_log', [ RootDB::db()->insert('member_log', [
'member_no'=>$userID, 'member_no'=>$userID,
'date'=>$nowDate, 'date'=>$now,
'action_type'=>'change_pw', 'action_type'=>'change_pw',
'action'=>Json::encode([ 'action'=>Json::encode([
'type'=>'kakao', 'type'=>'kakao',
+92
View File
@@ -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}회 더 시도할 수 있습니다."
]);
}
$tokenValidUntil = TimeUtil::DatetimeFromNowDay(10);
$session->setReqOTP(false);
RootDB::db()->update('member', [
'oauth_info'=>Json::encode($oauthInfo),
'token_valid_until'=>$tokenValidUntil,
], 'no=%i', $userNo);
Json::die([
'result'=>true,
'reset'=>false,
'reason'=>"로그인을 성공했습니다. {$tokenValidUntil}까지 유효합니다."
]);
+23 -5
View File
@@ -125,23 +125,35 @@ if(!$kakaoID && Util::array_get($signupResult['msg'])!='already registered'){
$me = $restAPI->meWithEmail(); $me = $restAPI->meWithEmail();
$me['code'] = Util::array_get($me['code'], 0); $me['code'] = Util::array_get($me['code'], 0);
$kakao_account = $me['kakao_account']??[];
if ($me['code']< 0) { if ($me['code']< 0) {
$restAPI->unlink(); $restAPI->unlink();
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.' 'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.',
]); ]);
} }
if(!Util::array_get($me['kaccount_email_verified'],false)){ if(!($kakao_account['has_email']??false)){
Json::die([
'result'=>false,
'reqOTP'=>false,
'reason'=>'이메일 정보 공유를 허가해 주셔야 합니다.',
]);
}
$validEmail = $kakao_account['is_email_valid']??false;
$verifiedEmail = $kakao_account['is_email_verified']??false;
if(!$validEmail || !$verifiedEmail){
$restAPI->unlink(); $restAPI->unlink();
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다' 'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다',
]); ]);
} }
$email = $me['kaccount_email']; $email = $kakao_account['email']??null;
$session->kaccount_email = $email; $session->kaccount_email = $email;
$emailChk = checkEmailDup($email); $emailChk = checkEmailDup($email);
if($emailChk !== true){ if($emailChk !== true){
@@ -162,7 +174,13 @@ RootDB::db()->insert('member',[
'pw' => $finalPassword, 'pw' => $finalPassword,
'salt' => $userSalt, 'salt' => $userSalt,
'name'=>$nickname, '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(); $userID = RootDB::db()->insertId();
+73 -12
View File
@@ -2,7 +2,7 @@
namespace sammo; namespace sammo;
require(__dir__.'/../vendor/autoload.php'); require(__dir__.'/../vendor/autoload.php');
require('lib.join.php');
use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper; use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper;
$RootDB = RootDB::db(); $RootDB = RootDB::db();
@@ -15,12 +15,13 @@ $canLogin = RootDB::db()->queryFirstField('SELECT `LOGIN` FROM `system` WHERE `N
if($canLogin != 'Y'){ if($canLogin != 'Y'){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'현재는 로그인이 금지되어있습니다!', 'reason'=>'현재는 로그인이 금지되어있습니다!',
'noRetry'=>true 'noRetry'=>true
]); ]);
} }
$nowDate = TimeUtil::DatetimeNow(); $now = TimeUtil::DatetimeNow();
$access_token = $session->access_token; $access_token = $session->access_token;
$expires = $session->expires; $expires = $session->expires;
@@ -32,6 +33,7 @@ $email = $session->kaccount_email;
if(!$access_token || !$expires){ if(!$access_token || !$expires){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'카카오로그인이 이루어지지 않았습니다.' 'reason'=>'카카오로그인이 이루어지지 않았습니다.'
]); ]);
} }
@@ -39,14 +41,15 @@ if(!$access_token || !$expires){
//TODO: join과 login의 동작이 비슷하다. helper class로 묶자. //TODO: join과 login의 동작이 비슷하다. helper class로 묶자.
$restAPI = new Kakao_REST_API_Helper($access_token); $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([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'로그인 토큰 만료.'.$refresh_token_expires.' 다시 카카오로그인을 수행해주세요.' 'reason'=>'로그인 토큰 만료.'.$refresh_token_expires.' 다시 카카오로그인을 수행해주세요.'
]); ]);
} }
if($expires < $nowDate){ if($expires < $now){
$session->kaccount_email = null; $session->kaccount_email = null;
$email = null; $email = null;
@@ -54,6 +57,7 @@ if($expires < $nowDate){
if(!isset($refresh_token)){ if(!isset($refresh_token)){
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다' 'reason'=>'카카오 로그인 과정 중 추가 갱신 절차를 실패했습니다'
]); ]);
} }
@@ -73,43 +77,68 @@ if(!$email){
if ($me['code']< 0) { if ($me['code']< 0) {
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>'카카오로그인이 정상적으로 수행되지 않았습니다.' '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'=>'이메일 정보 공유를 허가해 주셔야 합니다.',
]);
}
$validEmail = $kakao_account['is_email_valid']??false;
$verifiedEmail = $kakao_account['is_email_verified']??false;
if(!$validEmail || !$verifiedEmail){
$restAPI->unlink(); $restAPI->unlink();
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다' 'reqOTP'=>false,
'reason'=>'카카오 계정 이메일이 아직 인증되지 않았습니다',
]); ]);
} }
$email = $me['kaccount_email']; $email = $kakao_account['email'];
$session->kaccount_email = $email; $session->kaccount_email = $email;
} }
$userInfo = $RootDB->queryFirstRow( $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, token_valid_until from member where email=%s',$email);
if(!$userInfo){ if(!$userInfo){
$restAPI->unlink(); $restAPI->unlink();
$session->access_token = null; $session->access_token = null;
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>'카카오로그인에 해당하는 계정이 없습니다. 재 가입을 시도해주세요.' 'reqOTP'=>false,
'reason'=>'카카오로그인에 해당하는 계정이 없습니다. 재 가입을 시도해주세요.',
'aux'=>$session->tmpx,
]); ]);
} }
if($userInfo['delete_after']){ if($userInfo['delete_after']){
if($userInfo['delete_after'] < $nowDate){ if($userInfo['delete_after'] < $now){
$restAPI->unlink(); $restAPI->unlink();
$session->access_token = null; $session->access_token = null;
$RootDB->delete('member', 'no=%i', $userInfo['no']); $RootDB->delete('member', 'no=%i', $userInfo['no']);
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요." 'reqOTP'=>false,
'reason'=>"기간 만기로 삭제되었습니다. 재 가입을 시도해주세요.",
]); ]);
} }
else{ else{
@@ -117,12 +146,43 @@ if($userInfo['delete_after']){
$session->access_token = null; $session->access_token = null;
Json::die([ Json::die([
'result'=>false, 'result'=>false,
'reqOTP'=>false,
'reason'=>"삭제 요청된 계정입니다.[{$userInfo['delete_after']}]" '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']);
$tokenValidUntil = $userInfo['token_valid_until'];
if(!$tokenValidUntil || $tokenValidUntil < $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',[ $RootDB->insert('member_log',[
'member_no'=>$userInfo['no'], 'member_no'=>$userInfo['no'],
'action_type'=>'login', 'action_type'=>'login',
@@ -132,8 +192,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([ Json::die([
'result'=>true, 'result'=>true,
'reqOTP'=>false,
'reason'=>'로그인 되었습니다.' 'reason'=>'로그인 되었습니다.'
]); ]);
+44
View File
@@ -0,0 +1,44 @@
<?php
namespace sammo;
require(__dir__.'/../vendor/autoload.php');
use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper;
$session = Session::requireLogin([
'reason'=>'로그인이 되어있지 않습니다'
]);
$userID = Session::getUserID();
$tokenValidUntil = RootDB::db()->queryFirstField('SELECT token_valid_until from member where no=%i',$userID);
if(!$tokenValidUntil){
Json::die([
'result'=>false,
'reason'=>'초기화 가능한 로그인 상태가 아닙니다.'
]);
}
$now = TimeUtil::DatetimeNow();
$expectedDate = TimeUtil::DatetimeFromNowDay(5);
if($expectedDate <= $tokenValidUntil){
Json::die([
'result'=>false,
'reason'=>'아직 연장 가능하지 않습니다.'
]);
}
unset($oauthInfo['tokenValidUntil']);
RootDB::db()->update('member', [
'token_valid_until'=> null
], 'no=%i', $userID);
$session->logout();
Json::die([
'result'=>true,
'reason'=>'초기화 완료.'
]);
+65 -1
View File
@@ -1,5 +1,6 @@
<?php <?php
namespace sammo; namespace sammo;
use \kakao\Kakao_REST_API_Helper as Kakao_REST_API_Helper;
function checkUsernameDup($username){ function checkUsernameDup($username){
if(!$username){ if(!$username){
@@ -62,4 +63,67 @@ function checkEmailDup($email){
RootDB::db()->delete('member', 'no=%i', $userInfo['no']); RootDB::db()->delete('member', 'no=%i', $userInfo['no']);
} }
return true; 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];
}
+10 -2
View File
@@ -47,7 +47,15 @@ $me = $restAPI->meWithEmail();
$oauth_mode = 'login'; $oauth_mode = 'login';
$me['code'] = Util::array_get($me['code'], 0); $me['code'] = Util::array_get($me['code'], 0);
if($me['code']< 0){ $signed = $me['has_signed_up']??false;
$kakao_account = $me['kakao_account']??[];
if(!($kakao_account['has_email']??false)||!($kakao_account['email']??false)){
$oauth_mode = 'req_email';
}
else if(!$signed){
$oauth_mode = 'join';
}
else if($me['code']< 0){
switch(Util::array_get($me['msg'])){ switch(Util::array_get($me['msg'])){
case 'NotRegisteredUserException': case 'NotRegisteredUserException':
$oauth_mode = 'join'; $oauth_mode = 'join';
@@ -57,7 +65,7 @@ if($me['code']< 0){
} }
} }
else{ else{
$session->kaccount_email = $me['kaccount_email']; $session->kaccount_email = $kakao_account['email'];
} }
?> ?>
+1 -1
View File
@@ -1,7 +1,7 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="ko"> <html lang="ko">
<head> <head>
<meta charset="UTF-8">> <meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=1024" /> <meta name="viewport" content="width=1024" />
<title>OAuth 로그인 실패</title> <title>OAuth 로그인 실패</title>
+13 -9
View File
@@ -25,7 +25,7 @@ class User_Management_Path
public static $SIGNUP = "/v1/user/signup"; public static $SIGNUP = "/v1/user/signup";
public static $UNLINK = "/v1/user/unlink"; public static $UNLINK = "/v1/user/unlink";
public static $LOGOUT = "/v1/user/logout"; 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 $UPDATE_PROFILE = "/v1/user/update_profile";
public static $USER_IDS = "/v1/user/ids"; public static $USER_IDS = "/v1/user/ids";
} }
@@ -97,12 +97,12 @@ class Kakao_REST_API_Helper
$requestUrl .= '?'.$params; $requestUrl .= '?'.$params;
} }
$opts = array( $opts = [
CURLOPT_URL => $requestUrl, CURLOPT_URL => $requestUrl,
CURLOPT_RETURNTRANSFER => true, CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => false, CURLOPT_SSL_VERIFYPEER => false,
CURLOPT_SSLVERSION => 1, CURLOPT_SSLVERSION => CURL_SSLVERSION_TLSv1,
); ];
if ($api_path != '/oauth/token') { if ($api_path != '/oauth/token') {
if (in_array($api_path, self::$admin_apis)) { if (in_array($api_path, self::$admin_apis)) {
@@ -213,8 +213,12 @@ class Kakao_REST_API_Helper
public function meWithEmail() public function meWithEmail()
{ {
$params = [ $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); return $this->request(User_Management_Path::$ME);
} }
+14 -4
View File
@@ -8,12 +8,14 @@ namespace sammo;
* @property string $userName 유저명 * @property string $userName 유저명
* @property int $userGrade 유저등급 * @property int $userGrade 유저등급
* @property string $ip IP * @property string $ip IP
* @property bool $reqOTP 인증 코드 필요
* @property array $acl 권한 * @property array $acl 권한
*/ */
class Session class Session
{ {
const PROTECTED_NAMES = [ const PROTECTED_NAMES = [
'ip'=>true, 'ip'=>true,
'reqOTP'=>true,
'time'=>true, 'time'=>true,
'userID'=>true, 'userID'=>true,
'userName'=>true, 'userName'=>true,
@@ -163,7 +165,7 @@ class Session
return Util::array_get($_SESSION[$name]); 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('userID', $userID);
$this->set('userName', $userName); $this->set('userName', $userName);
@@ -171,10 +173,14 @@ class Session
$this->set('time', time()); $this->set('time', time());
$this->set('userGrade', $grade); $this->set('userGrade', $grade);
$this->set('acl', $acl); $this->set('acl', $acl);
$this->set('access_token', null); $this->set('reqOTP', $reqOTP);
return $this; return $this;
} }
public function setReqOTP(bool $reqOTP=false){
$this->set('reqOTP', $reqOTP);
}
public function logout(): Session public function logout(): Session
{ {
@@ -189,6 +195,7 @@ class Session
$this->set('userName', null); $this->set('userName', null);
$this->set('userGrade', null); $this->set('userGrade', null);
$this->set('acl', null); $this->set('acl', null);
$this->set('reqOTP', null);
$this->set('time', time()); $this->set('time', time());
return $this; return $this;
} }
@@ -324,9 +331,12 @@ class Session
return $obj->userID; 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; return true;
} else { } else {
return false; return false;