231 lines
7.7 KiB
PHP
231 lines
7.7 KiB
PHP
<?php
|
|
|
|
class Token extends BaseCode { //미니 접속유지용 토큰
|
|
|
|
private const Ezconst = "kuls_Auth_key"; //md5용 Hash (HashCode 생성용)
|
|
private const RdByte = 20; //랜덤 처리용 byte (Unique 발생용)
|
|
private static $Config = Array( //기본설정
|
|
"valid_time" => 3600, //토큰 유효시간 - 1시간
|
|
"expire_time" => 3600 * 24 * 3, //토큰 재발행 유효시간 3일. 이후 재로그인
|
|
"logging_time" => 3600 * 24 * 31 * 3, //로그보관 시간 3달 (현재미사용 - 나중에 로그쌓이는것 보고 사용여부 결정)
|
|
);
|
|
private const SpareTime = 120;
|
|
|
|
public function __construct( $cate_table="" ){
|
|
parent::__construct();
|
|
|
|
$this->DB->tableExists(TB_token_log);
|
|
}
|
|
|
|
|
|
/**
|
|
* putToken => 토큰 저장
|
|
* @param string $member_id : 로그인된 사용자 아이디
|
|
* @param string $auth : 인증코드. 각각의 로그인의 Unique세션으로 사용되며 Default는 요청마다 랜덤으로 새로 생성되지만, 인증키를 사용자 아이디로 고정으로 지정하면 중복접속 방지용으로 사용가능(Single Sign On)
|
|
* @param array $config : 기본설정 대체환경
|
|
*/
|
|
public function putToken( $member_id, $auth="", $config=Array() ){ //$auth 를 ID로 잡으면 Single Sign On, 그냥두면 Multi login
|
|
$member_id = trim($member_id);
|
|
if( !$member_id ) return false;
|
|
|
|
if( defined('_SINGLE_LOGIN_') && _SINGLE_LOGIN_ ){ //Single Sign On 적용
|
|
$auth = $member_id;
|
|
}else{
|
|
$auth = $auth ?: bin2hex(openssl_random_pseudo_bytes(self::RdByte)); //인증키 랜덤생성
|
|
}
|
|
$token = md5(self::Ezconst . $auth . uniqid()); //토큰생성
|
|
$config = $config + self::$Config;
|
|
|
|
$valid_time = time() + $config['valid_time'];
|
|
$exprie_time = time() + $config['expire_time'];
|
|
|
|
$this->retireToken($auth);
|
|
|
|
//$sql = "INSERT INTO ". TB_token_log ." (member_id, auth, token, valid_time, expire_time, active, ip) VALUES (?, ?, ?, ?, ?, ?, ?)";
|
|
$sqlrow = Array(
|
|
"member_id" => $member_id,
|
|
"auth" => $auth,
|
|
"token" => $token,
|
|
"valid_time" => $valid_time,
|
|
"expire_time" => $exprie_time,
|
|
"Active" => "Y",
|
|
"ip" => get_ip()
|
|
);
|
|
$rst = $this->DB->insert(TB_token_log, $sqlrow);
|
|
if( $rst ){
|
|
return $token;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* retireToken => 토큰 무효화. 비정상 접근시 사용
|
|
* @param string $auth : 인증코드. 해당 인증코드로 생성된 모든 토큰 무효화.
|
|
*/
|
|
public function retireToken( $auth ){//모든 $auth 비활성화 처리
|
|
//$sql = "UPDATE TB_token_log SET Active = 'N' WHERE Auth = ?";
|
|
$sqlrow = Array(
|
|
"active" => "N",
|
|
);
|
|
$where = new DB_where("and");
|
|
$where->add("auth = ?", $auth);
|
|
|
|
$wqry = $where->get_where();
|
|
$whereqry = $wqry['qry'];
|
|
$whererow = $wqry['val'];
|
|
|
|
return $this->DB->update(TB_token_log, $sqlrow, $whereqry, $whererow);
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* getFromToken => DB에서 토큰 관련정보 획득
|
|
* @param string $token : 사용자가 제출한 토큰.
|
|
*/
|
|
public function getFromToken( $token ){//Token 정보 Load
|
|
//$sql = "SELECT USER_ID, Auth, Valid_Time, Expire_Time, Active FROM TB_token_log WHERE Token = ?";
|
|
$where = new DB_where("and");
|
|
$where->add("token = ?", $token);
|
|
|
|
$wqry = $where->get_where();
|
|
$whereqry = $wqry['qry'];
|
|
$whererow = $wqry['val'];
|
|
|
|
$this->DB->query_record = false; //query log 기록 금지
|
|
$sql = "select member_id, auth, valid_time, expire_time, active from ". TB_token_log ." where {$whereqry}";
|
|
$row = $this->DB->queryFirstRow($sql, $whererow );
|
|
$this->DB->query_record = true; //query log 기록
|
|
|
|
return $row;
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
* getLastToken => DB에서 Auth 관련 최종정보 획득
|
|
* @param string $auth : 요청 인증.
|
|
*/
|
|
public function getLastAuth( $auth ){//Token 정보 Load
|
|
//$sql = "SELECT USER_ID, Auth, Valid_Time, Expire_Time, Active FROM TB_token_log WHERE Token = ?";
|
|
$where = new DB_where("and");
|
|
$where->add("auth = ?", $auth);
|
|
$where->add("active = ?", "Y");
|
|
|
|
$wqry = $where->get_where();
|
|
$whereqry = $wqry['qry'];
|
|
$whererow = $wqry['val'];
|
|
|
|
$this->DB->query_record = false; //query log 기록 금지
|
|
$sql = "select top 1 member_id, auth, valid_time, expire_time, active from ". TB_token_log ." where {$whereqry} order by valid_time desc";
|
|
$row = $this->DB->queryFirstRow($sql, $whererow );
|
|
$this->DB->query_record = true; //query log 기록
|
|
|
|
return $row;
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
* statusToken => Token의 현재상태 판단
|
|
* @param array|string $token_info : 토큰 또는 토큰 정보
|
|
* @return string
|
|
* Y: 인증성공
|
|
* N: 인증실패
|
|
* E: 연장필요 새로운 Token 발행
|
|
* F: 의심되는 접근. 전체 인증 Token 비활성화
|
|
*/
|
|
public function statusToken( $token_info ){//Token 상태 (Y:인증성공)
|
|
if( !is_array($token_info) ) $token_info = $this->getFromToken($token_info);
|
|
|
|
if( !$token_info['auth'] ) return 'N';
|
|
|
|
$now = time();
|
|
|
|
switch( true ){
|
|
case ( $token_info['expire_time'] < $now ) : //세션만료
|
|
return 'N'; //인증실패
|
|
case ( $token_info['valid_time'] >= $now ) : //유효시간 이내
|
|
if( trim($token_info['active']) != "Y" ) return "F"; //인증 비활성 필요
|
|
return 'Y'; //인증성공
|
|
case ( $token_info['expire_time'] >= $now ) :
|
|
if( trim($token_info['active']) != "Y" ){
|
|
if( ($token_info['expire_time'] + self::SpareTime) >= $now ){
|
|
return 'Y'; //동시 신호용 인증성공 $spare_time 초간 인정
|
|
}else{
|
|
return "F"; //인증 비활성 필요
|
|
}
|
|
}
|
|
return 'E'; //연장요청
|
|
}
|
|
|
|
return 'N';
|
|
}
|
|
|
|
|
|
public function chkToken( $token ){
|
|
|
|
//$fp = fopen(_UP_PATH_."/token_2t.txt", "a+");
|
|
|
|
//$fptxt = "=======================".PHP_EOL;
|
|
//$fptxt .= "NOW=> ".time().PHP_EOL;
|
|
//$fptxt .= "REQ=> ".print_r($_REQUEST,true).PHP_EOL;
|
|
|
|
$token_info = $this->getFromToken( $token );
|
|
$token_stauts = $this->statusToken($token_info);
|
|
//$fptxt .= "STATUS=> ".$token_stauts.PHP_EOL;
|
|
switch( $token_stauts ){
|
|
case "E" : //토큰 연장
|
|
$chk_token = $this->getLastAuth($token_info['auth']);
|
|
if( $token_info['token'] == $chk_token['token'] ){
|
|
$new_token = $this->putToken($token_info['member_id'], $token_info['auth']);
|
|
}
|
|
case "Y" : //토큰 유효
|
|
$_SESSION['auth_mem_id'] = $token_info['member_id'];
|
|
break;
|
|
|
|
// 토큰 연장처리 되어 새로운 토큰($new_token) 이 발행되었는데도 갱신하지 않고,
|
|
// 예전 토큰 그대로 사용하면 중복 인증요청으로 무효토큰 처리되니
|
|
// 새로운 토큰이 발행되면 다음 요청시엔 꼭 새로운 토큰으로 교체하는 과정이 필요.
|
|
// APP 에서 요청할때 응답이 필요한 요청이외의 단순 요청부분까지 응답을 필수 확인하여 $new_token 값이 있는지 점검후 교체하는 로직 필수!!
|
|
|
|
case "F" : //토큰 비활성
|
|
$this->retireToken( $token_info['auth'] );
|
|
case "N" : //토큰 무효
|
|
unset($_SESSION['auth_mem_id']);
|
|
break;
|
|
}
|
|
//fputs($fp, $fptxt);
|
|
//fclose($fp);
|
|
return $new_token;
|
|
}
|
|
|
|
|
|
/*
|
|
public static function getTokenLogin( $token, $config=Array() ){//Token 처리
|
|
$token_info = self::getToken($token);
|
|
$status = self::stateToken($token_info);
|
|
|
|
switch( $status ){
|
|
case "Y" :
|
|
$retval = $member;
|
|
break;
|
|
case "N" :
|
|
$retval = false;
|
|
break;
|
|
case "E" :
|
|
$token = self::putToken($token_info['member_id'], $token_info['auth'], $config);
|
|
$retval = $token;
|
|
break;
|
|
case "F" :
|
|
self::retireToken( $token_info['auth'] );
|
|
$retval = false;
|
|
break;
|
|
}
|
|
}
|
|
*/
|
|
} |