228 lines
7.0 KiB
PHP
Raw Normal View History

2024-08-31 01:03:37 +08:00
<?php
class clientTfaIndex extends Controller {
public function __construct() {
parent::__construct();
$this->pluginName = 'clientPlugin';
}
// 更新options
public function options($options) {
$tfaOpen = Model('SystemOption')->get('tfaOpen');
$tfaType = Model('SystemOption')->get('tfaType');
$options['system']['options']['tfaOpen'] = $tfaOpen == '1' ? 1 : 0;
$options['system']['options']['tfaType'] = $tfaType ? $tfaType : '';
return $options;
}
// 登录成功后(尚未更新登录状态)
public function loginAfter($user) {
// 避免死循环
$userInfo = Session::get('kodUser');
if($userInfo && isset($userInfo['userID']) && $userInfo['userID'] == $user['userID']) return;
if(!isset($this->in['withTfa']) || $this->in['withTfa']) return;
$tfaInfo = $this->getTfaInfo($user);
if (!$tfaInfo['tfaOpen']) return;
$key = md5($this->in['name'].$this->in['password'].'_'.$user['userID']);
Cache::set($key, $user);
show_json($tfaInfo);
}
// 入口方法
public function index(){
$check = array('tfaCode','tfaVerify');
$func = Input::get('action','in',null,$check);
$tfaIn = Input::get('tfaIn','json');
$key = md5($tfaIn['name'].$tfaIn['password'].'_'.$this->in['userID']);
$user = Cache::get($key);
if (!$user) show_json(LNG('client.tfa.userLgErr'), false, 10011);
if ($func == 'tfaCode') {
$this->tfaCode($user);
} else {
$this->tfaVerify($user);
}
}
/**
* 获取用户多重验证信息
*/
public function getTfaInfo($user){
$tfaOpen = Model('SystemOption')->get('tfaOpen');
$tfaType = Model('SystemOption')->get('tfaType');
$data = array(
'userID' => $user['userID'],
'tfaOpen' => intval($tfaOpen),
);
if (!$data['tfaOpen'] || !$tfaType) {
$data['tfaOpen'] = 0;
return $data;
}
// 发送类型,优先使用手机
$type = $input = '';
$typeArr = explode(',',$tfaType);
$typeArr = array_intersect(array('phone','email'), $typeArr);
foreach ($typeArr as $tType) {
$value = _get($user, $tType, '');
if (!$value) continue;
if (Input::check($value, $tType)) {
$type = $tType;
$input = $value;
break;
}
}
$tfaInfo = array(
'tfaType' => implode(',',$typeArr),
'type' => $type,
'input' => $this->getMscValue($input,$type)
);
return array_merge($data, $tfaInfo);
}
// 获取手机/邮箱(加*
private function getMscValue($value, $type){
if (!$value) return $value;
$slen = 3; $elen = 2;
if ($type == 'email') {
$epos = strripos($value,'@');
if ($epos <= 3) {
$slenList = array(1=>0,2=>1,3=>2);
$slen = $slenList[$epos];
}
$elen = strlen($value) - $epos - 1;
}
$rpls = substr($value, $slen, strlen($value) - $slen - $elen);
$rpld = str_repeat('*', strlen($rpls));
return substr($value, 0, $slen) . $rpld . substr($value, -$elen);
}
/**
* 发送验证码
*/
public function tfaCode($user) {
$data = $this->checkCode($user);
$this->sendCode($data);
}
private function checkCode($user) {
$data = Input::getArray(array(
'userID' => array('check' => 'int'),
'type' => array('check' => 'require'),
'input' => array('check' => 'require'),
'default' => array('default' => 0),
));
$type = $data['type'];
$input = $data['input'];
if($data['userID'] != $user['userID']) {
show_json(LNG('client.tfa.userLgErr'), false);
}
if($user[$type]){$input = $user[$type];}
if(!Input::check($input,$type)) {
show_json(LNG('client.tfa.sendInvalid'), false);
}
// 检测是否已被绑定;
if(!$user[$type] && $input){
$find = Model('User')->userSearch(array($type => $input));
$err = ($type == 'phone') ? LNG('ERROR_USER_EXIST_PHONE') : LNG('ERROR_USER_EXIST_EMAIL');
if($find){show_json($err, false);}
}
return array(
'type' => $type,
'input' => $input,
'source' => $this->pluginName.'_tfa_login',
);
}
// 发送验证码
private function sendCode($data) {
$type = $data['type'];
$input = $data['input'];
$source = $data['source'];
// 1.发送验证码
Action('user.setting')->checkMsgFreq($data); // 检查发送频率
if ($type == 'email') {
$res = Action('user.bind')->sendEmail($input, $type.'_'.$source);
} else {
$res = Action('user.bind')->sendSms($input, $type.'_'.$source);
}
if (!$res['code']) {
show_json(LNG('user.sendFail') . ': ' . $res['data'], false);
}
Action('user.setting')->checkMsgFreq($data, true);
// 3.存储验证码
$this->checkMsgCode($res['data'], $data, true);
show_json(LNG('user.sendSuccess'), true);
}
/**
* 证码存储、验证
* @param [type] $code
* @param array $data
* @param boolean $set
* @return void
*/
private function checkMsgCode($code, $data = array(), $set = false) {
$name = md5(implode('_', $data).'_msgcode');
// 1. 存储
if ($set) {
$sess = array(
'code' => $code,
'cnt' => 0,
'time' => time()
);
return Session::set($name, $sess);
}
// 2. 验证
if (!$sess = Session::get($name)) {
$msg = LNG('common.invalid') . LNG('user.code');
show_json($msg, false);
}
// 超过20分钟
if (($sess['time'] + 60 * 20) < time()) {
Session::remove($name);
show_json(LNG('user.codeExpired'), false);
}
// 错误次数过多,锁定一段时间——没有锁定,重新获取
if ($sess['cnt'] >= 10) {
Session::remove($name);
show_json(LNG('user.codeErrorTooMany'), false);
}
if (strtolower($sess['code']) != strtolower($code)) {
$sess['cnt'] ++;
Session::set($name, $sess);
show_json(LNG('user.codeError'), false);
}
Session::remove($name);
}
/**
* 提交验证码
*/
public function tfaVerify($user) {
// 验证码验证
if (!Input::get('wiotTfa',null,0)) {
$data = $this->checkCode($user);
$code = Input::get('code', 'require');
$this->checkMsgCode($code, $data);
// 绑定联系方式
if($user[$data['type']] != $data['input']) {
$update = array($data['type'] => $data['input']);
$res = Model('User')->userEdit($user['userID'], $update);
$user[$data['type']] = $data['input'];
}
}
// 删除用户缓存
$this->in = Input::get('tfaIn','json');
$key = md5($this->in['name'].$this->in['password'].'_'.$user['userID']);
Cache::remove($key);
// 更新登录状态
$this->in['withTfa'] = true;
Action("user.index")->loginSuccessUpdate($user);
show_json(LNG('common.loginSuccess'));
}
}