HANYANG_REACT/lib/base/token.class.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;
}
}
*/
}