298 lines
7.4 KiB
PHP
298 lines
7.4 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace Hura8\System\Model;
|
||
|
|
|
||
|
|
|
||
|
|
use Hura8\Database\iConnectDB;
|
||
|
|
use Hura8\System\IDGenerator;
|
||
|
|
|
||
|
|
class AuthModel
|
||
|
|
{
|
||
|
|
|
||
|
|
/* @var iConnectDB $db */
|
||
|
|
protected $db;
|
||
|
|
|
||
|
|
private $tb_login = '';
|
||
|
|
private $tb_access_code = '';
|
||
|
|
|
||
|
|
private $tb_onetime_key = '';
|
||
|
|
|
||
|
|
public function __construct($tb_login, $tb_access_code)
|
||
|
|
{
|
||
|
|
$this->tb_login = $tb_login;
|
||
|
|
$this->tb_access_code = $tb_access_code;
|
||
|
|
$this->db = get_db('', ENABLE_DB_DEBUG);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private const ACCESS_CODE_LENGTH = 30;
|
||
|
|
const ONE_TIME_KEY_LENGTH = 15;
|
||
|
|
|
||
|
|
|
||
|
|
public function checkOneTimeKey($auth_key) {
|
||
|
|
$db_response = $this->db->select(
|
||
|
|
$this->tb_onetime_key,
|
||
|
|
['user_id', 'user_name', 'client_id', 'create_time'],
|
||
|
|
[
|
||
|
|
'auth_key' => ["=", $auth_key],
|
||
|
|
],
|
||
|
|
'',
|
||
|
|
1
|
||
|
|
);
|
||
|
|
|
||
|
|
if($db_response->getCode()) {
|
||
|
|
return null;
|
||
|
|
}
|
||
|
|
|
||
|
|
$info = $db_response->getData();
|
||
|
|
|
||
|
|
if($info) {
|
||
|
|
|
||
|
|
// used ONCE and delete the key
|
||
|
|
$this->db->runQuery("DELETE FROM `".$this->tb_onetime_key."` WHERE `user_id` = ? ", ['s'], [$info['user_id']]);
|
||
|
|
|
||
|
|
return $info;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// auth key allows users to export data (i.e. export to excel) for offline use
|
||
|
|
public function createNewOneTimeKey($user_id) {
|
||
|
|
|
||
|
|
// and make a new one
|
||
|
|
$auth_key = IDGenerator::createStringId(self::ONE_TIME_KEY_LENGTH);
|
||
|
|
|
||
|
|
$this->db->insert($this->tb_onetime_key, [
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'auth_key' => $auth_key,
|
||
|
|
'create_time' => CURRENT_TIME,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $auth_key;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
// for all subsequent requests, API need to provide access-code in the request's header
|
||
|
|
// the server will verify the code
|
||
|
|
public function checkAccessCode($access_code) {
|
||
|
|
return $this->db->select(
|
||
|
|
$this->tb_access_code,
|
||
|
|
['user_id', 'create_time'],
|
||
|
|
[
|
||
|
|
'access_code' => ["=", $access_code],
|
||
|
|
],
|
||
|
|
'',
|
||
|
|
1
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public function deleteAllAccessCode($user_id) {
|
||
|
|
$this->db->runQuery("DELETE FROM `".$this->tb_access_code."` WHERE `user_id` = ? ", ['s'], [$user_id]);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected function createNewAccessCode($user_id) {
|
||
|
|
|
||
|
|
// when use login here, delete all other access code
|
||
|
|
$this->deleteAllAccessCode($user_id);
|
||
|
|
|
||
|
|
// and make a new one
|
||
|
|
$access_code = IDGenerator::createStringId(self::ACCESS_CODE_LENGTH);
|
||
|
|
$user_device = $_SERVER['HTTP_USER_AGENT'] ?? 'unknown';
|
||
|
|
|
||
|
|
$db_response = $this->db->insert($this->tb_access_code, [
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'access_code' => $access_code,
|
||
|
|
'user_device' => substr($user_device, 0, 150),
|
||
|
|
'create_time' => CURRENT_TIME,
|
||
|
|
]);
|
||
|
|
|
||
|
|
return $access_code;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* allow to login via mobile
|
||
|
|
* - step 1: sms an OTP code to mobile number
|
||
|
|
* - step 2: verify OTP code (mobile number and otp code sent along in the form)
|
||
|
|
*/
|
||
|
|
|
||
|
|
public function checkLoginViaMobile($mobile, $otp) {
|
||
|
|
// todo
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @description An OTP code is sent to user's email. This method helps user need not remember the password
|
||
|
|
* @param $email string
|
||
|
|
* @param $otp string
|
||
|
|
*/
|
||
|
|
|
||
|
|
public function checkLoginByOTP($user_id, $otp) {
|
||
|
|
$info = $this->db->select(
|
||
|
|
$this->tb_login,
|
||
|
|
[],
|
||
|
|
[
|
||
|
|
'user_id' => ["=", $user_id],
|
||
|
|
'login_otp' => ["=", $otp],
|
||
|
|
],
|
||
|
|
'',
|
||
|
|
1
|
||
|
|
);
|
||
|
|
|
||
|
|
if($info) {
|
||
|
|
// return to browser
|
||
|
|
return array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'access_code' => $this->createNewAccessCode($user_id),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public function createLoginOTP($user_id) {
|
||
|
|
// check email exist
|
||
|
|
$info = $this->db->select(
|
||
|
|
$this->tb_login,
|
||
|
|
[],
|
||
|
|
[
|
||
|
|
'user_id' => ["=", $user_id],
|
||
|
|
],
|
||
|
|
'',
|
||
|
|
1
|
||
|
|
);
|
||
|
|
|
||
|
|
if($info) {
|
||
|
|
$otp = IDGenerator::createStringId(6);
|
||
|
|
$this->db->update(
|
||
|
|
$this->tb_login,
|
||
|
|
[
|
||
|
|
'login_otp' => $otp
|
||
|
|
],
|
||
|
|
[
|
||
|
|
'user_id' => $info['user_id'],
|
||
|
|
]
|
||
|
|
);
|
||
|
|
|
||
|
|
return $otp;
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
public function createOrUpdatePassword($user_id, $new_password) {
|
||
|
|
$query = $this->db->runQuery(
|
||
|
|
"SELECT `user_id` FROM `".$this->tb_login."` WHERE `user_id` = ? LIMIT 1 ",
|
||
|
|
['d'], [ $user_id ]
|
||
|
|
);
|
||
|
|
|
||
|
|
if($this->db->fetchAssoc($query)) {
|
||
|
|
return $this->updatePassword($user_id, $new_password);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $this->createPassword($user_id, $new_password);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected function createPassword($user_id, $new_password) {
|
||
|
|
return $this->db->insert(
|
||
|
|
$this->tb_login,
|
||
|
|
[
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'password_hash' => $this->hashPassword($new_password),
|
||
|
|
'create_time' => CURRENT_TIME,
|
||
|
|
'create_by' => '',
|
||
|
|
]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
protected function updatePassword($user_id, $new_password) {
|
||
|
|
return $this->db->update(
|
||
|
|
$this->tb_login,
|
||
|
|
[
|
||
|
|
'password_hash' => $this->hashPassword($new_password),
|
||
|
|
'last_update' => CURRENT_TIME,
|
||
|
|
'last_update_by' => ADMIN_NAME,
|
||
|
|
],
|
||
|
|
[
|
||
|
|
'user_id' => $user_id,
|
||
|
|
]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $user_id int
|
||
|
|
* @param $password string
|
||
|
|
* @return array|false
|
||
|
|
*/
|
||
|
|
public function checkLogin($user_id, $password) {
|
||
|
|
|
||
|
|
$info = $this->db->select(
|
||
|
|
$this->tb_login,
|
||
|
|
[ 'password_hash'],
|
||
|
|
[
|
||
|
|
'user_id' => ["=", $user_id],
|
||
|
|
],
|
||
|
|
'',
|
||
|
|
1
|
||
|
|
);
|
||
|
|
|
||
|
|
//test password
|
||
|
|
if($info && $this->verifyHash($password, $info['password_hash'])) {
|
||
|
|
|
||
|
|
$this->updateUserLogin($user_id);
|
||
|
|
|
||
|
|
// return to browser
|
||
|
|
return array(
|
||
|
|
'user_id' => $user_id,
|
||
|
|
'access_code' => $this->createNewAccessCode($user_id),
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
private function updateUserLogin($user_id){
|
||
|
|
return $this->db->update(
|
||
|
|
$this->tb_login,
|
||
|
|
[
|
||
|
|
'last_login_time' => CURRENT_TIME,
|
||
|
|
'last_login_ip' => USER_IP,
|
||
|
|
'last_login_device' => '',
|
||
|
|
'last_login_session_id' => \Hura8\System\Security\Session::id() ?: '',
|
||
|
|
'last_login_browser' => USER_AGENT,
|
||
|
|
],
|
||
|
|
[
|
||
|
|
'user_id' => $user_id,
|
||
|
|
]
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $str string
|
||
|
|
* @return string
|
||
|
|
*/
|
||
|
|
private function hashPassword($str) {
|
||
|
|
return password_hash($str, PASSWORD_BCRYPT, array('cost' => 12 ));
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 15-04-2016 verify string with given hash
|
||
|
|
* @param $str_to_verify string
|
||
|
|
* @param $hash string
|
||
|
|
* @return boolean
|
||
|
|
*/
|
||
|
|
private function verifyHash($str_to_verify, $hash) {
|
||
|
|
return (password_verify($str_to_verify, $hash));
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|