머지
This commit is contained in:
+6
-2
@@ -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;
|
||||||
|
|||||||
Vendored
+2
-2
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Vendored
+3
-3
File diff suppressed because one or more lines are too long
@@ -52,6 +52,7 @@ $rootDB->insert('member',[
|
|||||||
'oauth_type' => 'NONE',
|
'oauth_type' => 'NONE',
|
||||||
'id' => $username,
|
'id' => $username,
|
||||||
'email' => null,
|
'email' => null,
|
||||||
|
'token_valid_until'=>'2999-01-01 00:00:00',
|
||||||
'pw' => $finalPassword,
|
'pw' => $finalPassword,
|
||||||
'salt' => $userSalt,
|
'salt' => $userSalt,
|
||||||
'grade'=> 6,
|
'grade'=> 6,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -54,9 +54,6 @@ if ($showCurrentNation) {
|
|||||||
<tr>
|
<tr>
|
||||||
<td style="background-color:#333333;" align=center colspan=8>
|
<td style="background-color:#333333;" align=center colspan=8>
|
||||||
<font size=5>현재 (<?=$year?>年 <?=$month?>月)</font>
|
<font size=5>현재 (<?=$year?>年 <?=$month?>月)</font>
|
||||||
|
|
||||||
<a href="a_emperior_detail.php"><button>자세히</button></a>
|
|
||||||
|
|
||||||
<a href="a_history.php"><button>역사 보기</button></a>
|
<a href="a_history.php"><button>역사 보기</button></a>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ $serverID = $emperior['server_id']??($emperior['serverID']??null);
|
|||||||
|
|
||||||
<body>
|
<body>
|
||||||
<table align=center width=1000 class="tb_layout bg0">
|
<table align=center width=1000 class="tb_layout bg0">
|
||||||
<tr><td><?=$emperior?'역 대 왕 조':'현 재 왕 조'?><br>
|
<tr><td>역 대 왕 조<br>
|
||||||
<button onclick=window.close()>창 닫기</button>
|
<button onclick=window.close()>창 닫기</button>
|
||||||
<div style="float:right;"><a href="a_emperior.php"><button>전체보기</button></a><div>
|
<div style="float:right;"><a href="a_emperior.php"><button>전체보기</button></a><div>
|
||||||
</td></tr>
|
</td></tr>
|
||||||
@@ -160,7 +160,7 @@ if($emperior):
|
|||||||
<?php
|
<?php
|
||||||
endif;
|
endif;
|
||||||
|
|
||||||
$showServers = $serverID || (!$emperior);
|
$showServers = $emperior;
|
||||||
|
|
||||||
if(!$serverID){
|
if(!$serverID){
|
||||||
$serverID = UniqueConst::$serverID;
|
$serverID = UniqueConst::$serverID;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ extractMissingPostToGlobals();
|
|||||||
//로그인 검사
|
//로그인 검사
|
||||||
$session = Session::requireGameLogin()->setReadOnly();
|
$session = Session::requireGameLogin()->setReadOnly();
|
||||||
$userID = Session::getUserID();
|
$userID = Session::getUserID();
|
||||||
|
$userGrade = Session::getUserGrade();
|
||||||
|
|
||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$connect=$db->get();
|
$connect=$db->get();
|
||||||
@@ -168,7 +169,7 @@ echo "
|
|||||||
unset($city);
|
unset($city);
|
||||||
|
|
||||||
// 첩보된 도시까지만 허용
|
// 첩보된 도시까지만 허용
|
||||||
if($valid == 0 && $session->userGrade < 5) {
|
if($valid == 0 && $userGrade < 5) {
|
||||||
$citylist = $me['city'];
|
$citylist = $me['city'];
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -212,6 +213,10 @@ for($j=0; $j < $gencount; $j++) {
|
|||||||
$ourGeneral = false;
|
$ourGeneral = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if($userGrade == 6){
|
||||||
|
$ourGeneral = true;
|
||||||
|
}
|
||||||
|
|
||||||
$isNPC = $general['npc']>1;
|
$isNPC = $general['npc']>1;
|
||||||
$wounded = $general['injury'];
|
$wounded = $general['injury'];
|
||||||
|
|
||||||
|
|||||||
+1
-1
@@ -111,7 +111,7 @@ function myCommandList() {
|
|||||||
echo "
|
echo "
|
||||||
<tr height=28>
|
<tr height=28>
|
||||||
<td width=24 align=center height=24 id=bg0><b>$j</b></td>
|
<td width=24 align=center height=24 id=bg0><b>$j</b></td>
|
||||||
<td width=71 align=center height=24 id=bg1><b>{$year}年 {$month}月</b></td>
|
<td width=71 align=center height=24 id=bg1 style='overflow:hidden;'><b>{$year}年 {$month}月</b></td>
|
||||||
<td width=42 align=center bgcolor=black><b>$turndate</b></td>
|
<td width=42 align=center bgcolor=black><b>$turndate</b></td>
|
||||||
<td width=150 align=center height=24 style=table-layout:fixed;>$turn[$i]</td>
|
<td width=150 align=center height=24 style=table-layout:fixed;>$turn[$i]</td>
|
||||||
</tr>";
|
</tr>";
|
||||||
|
|||||||
+3
-2
@@ -416,7 +416,7 @@ function addCommand($typename, $value, $valid = 1, $color=0) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
echo "
|
echo "
|
||||||
<option style=color:white;background-color:red; value={$value}>{$typename}</option>";
|
<option style=color:white;background-color:red; value={$value}>{$typename}(불가)</option>";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1244,6 +1244,7 @@ function increaseRefresh($type="", $cnt=1) {
|
|||||||
$session = Session::getInstance();
|
$session = Session::getInstance();
|
||||||
$userID = $session->userID;
|
$userID = $session->userID;
|
||||||
$generalID = $session->generalID;
|
$generalID = $session->generalID;
|
||||||
|
$userGrade = $session->userGrade;
|
||||||
|
|
||||||
$date = date('Y-m-d H:i:s');
|
$date = date('Y-m-d H:i:s');
|
||||||
|
|
||||||
@@ -1251,7 +1252,7 @@ function increaseRefresh($type="", $cnt=1) {
|
|||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
$gameStor->refresh = $gameStor->refresh+$cnt; //TODO: +로 증가하는 값은 별도로 분리
|
$gameStor->refresh = $gameStor->refresh+$cnt; //TODO: +로 증가하는 값은 별도로 분리
|
||||||
|
|
||||||
if($generalID) {
|
if($generalID && $userGrade < 6) {
|
||||||
$db->update('general', [
|
$db->update('general', [
|
||||||
'lastrefresh'=>$date,
|
'lastrefresh'=>$date,
|
||||||
'con'=>$db->sqleval('con + %i', $cnt),
|
'con'=>$db->sqleval('con + %i', $cnt),
|
||||||
|
|||||||
+2
-2
@@ -232,10 +232,10 @@ else if($session->userGrade == 4){
|
|||||||
</table>
|
</table>
|
||||||
<table class="tb_layout bg0" style="width:1000px;">
|
<table class="tb_layout bg0" style="width:1000px;">
|
||||||
<tr>
|
<tr>
|
||||||
<td width=698 height=520 colspan=2>
|
<td style='width:700px;height:520px;' colspan=2>
|
||||||
<?=getMapHtml($mapTheme)?>
|
<?=getMapHtml($mapTheme)?>
|
||||||
</td>
|
</td>
|
||||||
<td width=298 rowspan=4><iframe seamless="seamless" name=commandlist src='commandlist.php' width=298 height=700 frameborder=0 marginwidth=0 marginheight=0 topmargin=0 scrolling=no></iframe></td>
|
<td style='width:300px;' rowspan=4><iframe seamless="seamless" name=commandlist src='commandlist.php' style='width:300px;height:700px;' frameborder=0 marginwidth=0 marginheight=0 topmargin=0 scrolling=no></iframe></td>
|
||||||
</tr>
|
</tr>
|
||||||
<form name=form2 action=preprocessing.php method=post target=commandlist>
|
<form name=form2 action=preprocessing.php method=post target=commandlist>
|
||||||
<tr>
|
<tr>
|
||||||
|
|||||||
+3
-1
@@ -153,6 +153,8 @@ jQuery(function($){
|
|||||||
|
|
||||||
var customCSS = localStorage.getItem('sam_customCSS');
|
var customCSS = localStorage.getItem('sam_customCSS');
|
||||||
if(customCSS){
|
if(customCSS){
|
||||||
$('<style type="text/css">\n'+customCSS+'\n</style>').appendTo($('head'));
|
var $style = $('<style type="text/css"></style>');
|
||||||
|
$style.text(customCSS);
|
||||||
|
$style.appendTo($('head'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|||||||
+5
-5
@@ -1624,13 +1624,13 @@ function command_53($turn, $command) {
|
|||||||
$result = MYDB_query($query, $connect) or Error("aaa_processing.php ".MYDB_error($connect),"");
|
$result = MYDB_query($query, $connect) or Error("aaa_processing.php ".MYDB_error($connect),"");
|
||||||
$count = MYDB_num_rows($result);
|
$count = MYDB_num_rows($result);
|
||||||
|
|
||||||
$cond1 = round((-0.25 * $stdNation['power']) + $avgNation['power'], 2);
|
$cond1 = (-0.25 * $stdNation['power']) + $avgNation['power'];
|
||||||
$cond2 = round((-0.67 * $stdNation['gennum']) + $avgNation['gennum'], 2);
|
$cond2 = (-0.67 * $stdNation['gennum']) + $avgNation['gennum'];
|
||||||
|
|
||||||
for($i=1; $i <= $count; $i++) {
|
for($i=1; $i <= $count; $i++) {
|
||||||
$nation = MYDB_fetch_array($result);
|
$nation = MYDB_fetch_array($result);
|
||||||
|
|
||||||
if($myNation['power']+$nation['power'] > $cond1 || $myNation['gennum']+$nation['gennum'] > $cond2 || !isNeighbor($me['nation'], $nation['nation'])) {
|
if(($myNation['power']+$nation['power'])/2 > $cond1 || ($myNation['gennum']+$nation['gennum'])/2 > $cond2 || !isNeighbor($me['nation'], $nation['nation'])) {
|
||||||
echo "<option style=color:{$nation['color']};background-color:red; value={$nation['nation']}>【 {$nation['name']} 】</option>";
|
echo "<option style=color:{$nation['color']};background-color:red; value={$nation['nation']}>【 {$nation['name']} 】</option>";
|
||||||
} else {
|
} else {
|
||||||
echo "<option style=color:{$nation['color']} value={$nation['nation']}>【 {$nation['name']} 】</option>";
|
echo "<option style=color:{$nation['color']} value={$nation['nation']}>【 {$nation['name']} 】</option>";
|
||||||
@@ -1652,8 +1652,8 @@ function command_53($turn, $command) {
|
|||||||
제한 조건<br>
|
제한 조건<br>
|
||||||
- 인접 국가<br>
|
- 인접 국가<br>
|
||||||
- 양국 모두 외교제한 없음<br>
|
- 양국 모두 외교제한 없음<br>
|
||||||
- 두 국가의 국력 평균이 상위 60%(현재 {$cond1}) 이하.<br>
|
- 두 국가의 국력 평균이 상위 60%(현재 ".round($cond1,2).") 이하.<br>
|
||||||
- 두 국가의 장수수 평균이 상위 75%(현재 {$cond2} 이하.<br>
|
- 두 국가의 장수수 평균이 상위 75%(현재 ".round($cond2,1).") 이하.<br>
|
||||||
";
|
";
|
||||||
ender(1);
|
ender(1);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -181,7 +181,7 @@ class DiplomaticMessage extends Message{
|
|||||||
$josaWa = JosaUtil::pick($this->src->nationName, '와');
|
$josaWa = JosaUtil::pick($this->src->nationName, '와');
|
||||||
pushGeneralHistory(
|
pushGeneralHistory(
|
||||||
['no'=>$this->dest->generalID],
|
['no'=>$this->dest->generalID],
|
||||||
["<C>●</>{$helper->year}년 {$helper->month}월:<D><b>{$this->src->nationName}</b></>{$josaWa} 통합 시도"]
|
"<C>●</>{$helper->year}년 {$helper->month}월:<D><b>{$this->src->nationName}</b></>{$josaWa} 통합 시도"
|
||||||
);
|
);
|
||||||
pushGenLog(
|
pushGenLog(
|
||||||
['no'=>$this->dest->generalID],
|
['no'=>$this->dest->generalID],
|
||||||
@@ -200,7 +200,7 @@ class DiplomaticMessage extends Message{
|
|||||||
$josaWa = JosaUtil::pick($this->dest->nationName, '와');
|
$josaWa = JosaUtil::pick($this->dest->nationName, '와');
|
||||||
pushGeneralHistory(
|
pushGeneralHistory(
|
||||||
['no'=>$this->src->generalID],
|
['no'=>$this->src->generalID],
|
||||||
["<C>●</>{$helper->year}년 {$helper->month}월:<D><b>{$this->dest->nationName}</b></>{$josaWa} 통합 시도"]
|
"<C>●</>{$helper->year}년 {$helper->month}월:<D><b>{$this->dest->nationName}</b></>{$josaWa} 통합 시도"
|
||||||
);
|
);
|
||||||
$josaYi = JosaUtil::pick($this->dest->nationName, '이');
|
$josaYi = JosaUtil::pick($this->dest->nationName, '이');
|
||||||
pushGenLog(
|
pushGenLog(
|
||||||
|
|||||||
@@ -29,12 +29,12 @@ class Diplomacy{
|
|||||||
$db = DB::db();
|
$db = DB::db();
|
||||||
$gameStor = KVStorage::getStorage($db, 'game_env');
|
$gameStor = KVStorage::getStorage($db, 'game_env');
|
||||||
$srcNation = $db->queryFirstRow(
|
$srcNation = $db->queryFirstRow(
|
||||||
'SELECT nation, `name`, `power`, capital, gold, rice, surlimit, color, `level` FROM nation WHERE nation=%i',
|
'SELECT nation, `name`, `power`, capital, gold, rice, gennum, surlimit, color, `level` FROM nation WHERE nation=%i',
|
||||||
$srcNationID
|
$srcNationID
|
||||||
);
|
);
|
||||||
|
|
||||||
$destNation = $db->queryFirstRow(
|
$destNation = $db->queryFirstRow(
|
||||||
'SELECT nation, `name`, `power`, capital, gold, rice, surlimit, color, `level` FROM nation WHERE nation=%i',
|
'SELECT nation, `name`, `power`, capital, gold, rice, gennum, surlimit, color, `level` FROM nation WHERE nation=%i',
|
||||||
$destNationID
|
$destNationID
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -592,7 +592,7 @@ class WarUnitGeneral extends WarUnit{
|
|||||||
}
|
}
|
||||||
|
|
||||||
if($oppose instanceof WarUnitCity){
|
if($oppose instanceof WarUnitCity){
|
||||||
$magic = Util::choiceRandom(['급습', '위보',' 혼란']);
|
$magic = Util::choiceRandom(['급습', '위보', '혼란']);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
$magic = Util::choiceRandom(['위보', '매복', '반목', '화계', '혼란']);
|
$magic = Util::choiceRandom(['위보', '매복', '반목', '화계', '혼란']);
|
||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
]);
|
]);
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
@@ -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,29 +170,62 @@ 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="카카오톡으로 가입&로그인"></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">
|
<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>
|
||||||
<!--
|
|
||||||
<div class="form-group row">
|
|
||||||
<div class="col-sm-4"><a href="javascript:getOAuthToken('change_pw', 'talk_message');">비밀번호 찾기<img src="oauth_kakao/kakao_to_me.png"></a></div>
|
|
||||||
<div class="col-sm-8">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<div id="bottom_box">
|
<div id="bottom_box">
|
||||||
<div class="container"><a href="terms.2.html">개인정보처리방침</a> & <a href="terms.1.html">이용약관</a><br>© 2018 • HideD
|
<div class="container"><a href="terms.2.html">개인정보처리방침</a> & <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">×</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>
|
||||||
|
|||||||
+100
-2
@@ -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,92 @@ $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 = $userInfo['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']??null;
|
||||||
|
|
||||||
|
if(!$accessToken){
|
||||||
|
trigger_error("refreshToken 에러 ".Json::encode($refreshResult).",".$refreshToken.",".substr(\kakao\KakaoKey::REST_KEY, 0, 6), E_USER_NOTICE);
|
||||||
|
return [false, '로그인 토큰 자동 갱신을 실패했습니다. 카카오 로그인을 수행해 주세요.'];
|
||||||
|
}
|
||||||
|
$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 = Session::getInstance();
|
||||||
|
$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, token_valid_until '.
|
||||||
'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 +113,7 @@ $userInfo = $RootDB->queryFirstRow(
|
|||||||
if(!$userInfo){
|
if(!$userInfo){
|
||||||
Json::die([
|
Json::die([
|
||||||
'result'=>false,
|
'result'=>false,
|
||||||
|
'reqOTP'=>false,
|
||||||
'reason'=>'아이디나 비밀번호가 올바르지 않습니다.'
|
'reason'=>'아이디나 비밀번호가 올바르지 않습니다.'
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
@@ -49,12 +132,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 +155,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, $userInfo['token_valid_until'], 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, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
|
||||||
Json::die([
|
Json::die([
|
||||||
'result'=>true,
|
'result'=>true,
|
||||||
|
'reqOTP'=>false,
|
||||||
'reason'=>'로그인 되었습니다.'
|
'reason'=>'로그인 되었습니다.'
|
||||||
]);
|
]);
|
||||||
+1
-1
@@ -111,7 +111,7 @@ $(document).ready( function () {
|
|||||||
alert(obj.reason);
|
alert(obj.reason);
|
||||||
}
|
}
|
||||||
else{
|
else{
|
||||||
alert('정상적으로 가입되었습니다.');
|
alert('회원 등록되었습니다.\n첫 로그인 과정에서 인증 코드를 입력하는 것으로 계정이 활성화됩니다.');
|
||||||
}
|
}
|
||||||
|
|
||||||
window.location.href = "../";
|
window.location.href = "../";
|
||||||
|
|||||||
+36
-4
@@ -48,14 +48,46 @@ $(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{
|
|
||||||
window.location.href = 'i_entrance/entrance.php';
|
var $modal = $('#modalOTP').modal();
|
||||||
}
|
$modal.on('shown.bs.modal', function(){
|
||||||
|
$('#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;
|
||||||
|
})
|
||||||
} );
|
} );
|
||||||
@@ -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);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -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
@@ -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',
|
||||||
|
|||||||
@@ -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, $tokenValidUntil);
|
||||||
|
RootDB::db()->update('member', [
|
||||||
|
'oauth_info'=>Json::encode($oauthInfo),
|
||||||
|
'token_valid_until'=>$tokenValidUntil,
|
||||||
|
], 'no=%i', $userNo);
|
||||||
|
|
||||||
|
Json::die([
|
||||||
|
'result'=>true,
|
||||||
|
'reset'=>false,
|
||||||
|
'reason'=>"로그인을 성공했습니다. {$tokenValidUntil}까지 유효합니다."
|
||||||
|
]);
|
||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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,45 @@ 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['accessTokenValidUntil'] = $expires;
|
||||||
|
if($refresh_token){
|
||||||
|
$oauthInfo['refreshToken'] = $refresh_token;
|
||||||
|
$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, $userInfo['token_valid_until'], 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 +194,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, $userInfo['token_valid_until'], Json::decode($userInfo['acl']??'{}'));
|
||||||
Json::die([
|
Json::die([
|
||||||
'result'=>true,
|
'result'=>true,
|
||||||
|
'reqOTP'=>false,
|
||||||
'reason'=>'로그인 되었습니다.'
|
'reason'=>'로그인 되었습니다.'
|
||||||
]);
|
]);
|
||||||
@@ -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'=>'초기화 완료.'
|
||||||
|
]);
|
||||||
@@ -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
@@ -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,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>
|
||||||
|
|||||||
@@ -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)) {
|
||||||
@@ -182,8 +182,7 @@ class Kakao_REST_API_Helper
|
|||||||
$params = [
|
$params = [
|
||||||
'grant_type'=>'refresh_token',
|
'grant_type'=>'refresh_token',
|
||||||
'client_id'=>$this->REST_KEY,
|
'client_id'=>$this->REST_KEY,
|
||||||
'redirect_uri'=>$this->REDIRECT_URI,
|
'refresh_token'=>$refresh_token
|
||||||
'code'=>$refresh_token
|
|
||||||
];
|
];
|
||||||
$result = $this->_create_or_refresh_access_token($params);
|
$result = $this->_create_or_refresh_access_token($params);
|
||||||
|
|
||||||
@@ -213,8 +212,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+27
-3
@@ -8,12 +8,15 @@ 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 권한
|
||||||
|
* @property string $tokenValidUntil 로그인 토큰 길이
|
||||||
*/
|
*/
|
||||||
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,
|
||||||
@@ -21,6 +24,7 @@ class Session
|
|||||||
'writeClosed'=>true,
|
'writeClosed'=>true,
|
||||||
'generalID'=>true,
|
'generalID'=>true,
|
||||||
'generalName'=>true,
|
'generalName'=>true,
|
||||||
|
'tokenValidUntil'=>true,
|
||||||
'acl'=>true
|
'acl'=>true
|
||||||
];
|
];
|
||||||
|
|
||||||
@@ -163,7 +167,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, ?string $tokenValidUntil, array $acl): Session
|
||||||
{
|
{
|
||||||
$this->set('userID', $userID);
|
$this->set('userID', $userID);
|
||||||
$this->set('userName', $userName);
|
$this->set('userName', $userName);
|
||||||
@@ -171,10 +175,16 @@ 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);
|
||||||
|
$this->set('tokenValidUntil', $tokenValidUntil);
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function setReqOTP(bool $reqOTP=false, string $tokenValidUntil){
|
||||||
|
$this->set('reqOTP', $reqOTP);
|
||||||
|
$this->set('tokenValidUntil', $tokenValidUntil);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public function logout(): Session
|
public function logout(): Session
|
||||||
{
|
{
|
||||||
@@ -189,6 +199,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,8 +335,21 @@ class Session
|
|||||||
return $obj->userID;
|
return $obj->userID;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function isLoggedIn(): bool
|
public function isLoggedIn(bool $ignoreOTP = false): bool
|
||||||
{
|
{
|
||||||
|
if(!$ignoreOTP){
|
||||||
|
if($this->reqOTP){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if(!$this->tokenValidUntil){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
$now = TimeUtil::DatetimeNow();
|
||||||
|
if($this->tokenValidUntil < $now){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($this->userID) {
|
if ($this->userID) {
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user