2024-08-31 01:03:37 +08:00

228 lines
7.0 KiB
PHP
Executable File
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<?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'));
}
}