diff --git a/src/admin/api.php b/src/admin/api.php new file mode 100644 index 00000000..6515db4d --- /dev/null +++ b/src/admin/api.php @@ -0,0 +1,21 @@ +isNeedCheckCode($userid); + echo json_encode(array( + "code" => 0, + "msg" => "", + "data" => array( + "isNeed" => $isNeed, + ), + )); + exit; +} \ No newline at end of file diff --git a/src/admin/js/login.js b/src/admin/js/login.js new file mode 100644 index 00000000..8f4b92aa --- /dev/null +++ b/src/admin/js/login.js @@ -0,0 +1,17 @@ +$(document).ready(function () { + $("#iptUserid").focusout(function () { + let userid = $(this).val(); + if (userid !== '') { + $.get("api.php?action=is_need_check_code&userid=" + userid, function (data) { + let rs = JSON.parse(data); + if (rs.code === 0) { + if (rs.data.isNeed) { + $("#vdimgck").show(); + } else { + $("#vdimgck").hide(); + } + } + }); + } + }) +}) \ No newline at end of file diff --git a/src/admin/login.php b/src/admin/login.php index e7cdb129..0a7e499a 100644 --- a/src/admin/login.php +++ b/src/admin/login.php @@ -38,10 +38,19 @@ if (preg_match('/admin\/login/i', $cururl)) { $admindirs = explode('/', str_replace("\\", '/', dirname(__FILE__))); $admindir = $admindirs[count($admindirs) - 1]; if ($dopost == 'login') { - $validate = empty($validate) ? '' : strtolower(trim($validate)); - $svali = strtolower(GetCkVdValue()); $cuserLogin = new userLogin($admindir); if (!empty($userid) && !empty($pwd)) { + $isNeed = $cuserLogin->isNeedCheckCode($userid); + if ($isNeed) { + $validate = empty($validate) ? '' : strtolower(trim($validate)); + $svali = strtolower(GetCkVdValue()); + if ($validate == '' || $validate != $svali) { + ResetVdValue(); + ShowMsg('验证码不正确', 'login.php', 0, 1000); + exit; + } + } + $res = $cuserLogin->checkUser($userid, $pwd); if ($res == 1) { $cuserLogin->keepUser(); diff --git a/src/admin/templets/login.htm b/src/admin/templets/login.htm index ac2ec1db..b832fb37 100644 --- a/src/admin/templets/login.htm +++ b/src/admin/templets/login.htm @@ -9,6 +9,8 @@ + + @@ -44,6 +46,13 @@ +
diff --git a/src/install/sql-dftables.txt b/src/install/sql-dftables.txt index ba4d1e5d..6afa1357 100755 --- a/src/install/sql-dftables.txt +++ b/src/install/sql-dftables.txt @@ -128,6 +128,7 @@ CREATE TABLE `#@__admin` ( `typeid` text, `logintime` int(10) unsigned NOT NULL default '0', `loginip` varchar(46) NOT NULL default '', + `loginerr` tinyint NULL DEFAULT 0, PRIMARY KEY (`id`) ) TYPE=MyISAM; @@ -503,6 +504,7 @@ CREATE TABLE `#@__member` ( `logintime` int(10) unsigned NOT NULL default '0', `loginip` char(46) NOT NULL default '', `checkmail` smallint(6) NOT NULL default '-1', + `loginerr` tinyint NULL DEFAULT 0, PRIMARY KEY (`mid`), KEY `userid` (`userid`,`sex`), KEY `logintime` (`logintime`) diff --git a/src/install/update.txt b/src/install/update.txt index 40280bbd..fdaf8757 100644 --- a/src/install/update.txt +++ b/src/install/update.txt @@ -103,4 +103,6 @@ DELETE FROM `#@__sysconfig` WHERE `#@__sysconfig`.`varname` = 'cfg_disable_tags' DELETE FROM `#@__sysconfig` WHERE `#@__sysconfig`.`varname` = 'cfg_vdcode_member'; -- 6.2.0 -ALTER TABLE `#@__arctype` CHANGE COLUMN `iscross` `cross` tinyint(1) NOT NULL DEFAULT 0 AFTER `ishidden`; \ No newline at end of file +ALTER TABLE `#@__arctype` CHANGE COLUMN `iscross` `cross` tinyint(1) NOT NULL DEFAULT 0 AFTER `ishidden`; +ALTER TABLE `#@__admin` ADD COLUMN `loginerr` tinyint NULL DEFAULT 0 AFTER `loginip`; +ALTER TABLE `#@__member` ADD COLUMN `loginerr` tinyint NULL DEFAULT 0 AFTER `checkmail`; \ No newline at end of file diff --git a/src/static/web/js/login.js b/src/static/web/js/login.js new file mode 100644 index 00000000..8f4b92aa --- /dev/null +++ b/src/static/web/js/login.js @@ -0,0 +1,17 @@ +$(document).ready(function () { + $("#iptUserid").focusout(function () { + let userid = $(this).val(); + if (userid !== '') { + $.get("api.php?action=is_need_check_code&userid=" + userid, function (data) { + let rs = JSON.parse(data); + if (rs.code === 0) { + if (rs.data.isNeed) { + $("#vdimgck").show(); + } else { + $("#vdimgck").hide(); + } + } + }); + } + }) +}) \ No newline at end of file diff --git a/src/system/memberlogin.class.php b/src/system/memberlogin.class.php index e11240aa..3514dd41 100755 --- a/src/system/memberlogin.class.php +++ b/src/system/memberlogin.class.php @@ -391,8 +391,10 @@ class MemberLogin $row = $dsql->GetOne("SELECT mid,matt,pwd,pwd_new,logintime FROM `#@__member` WHERE userid LIKE '$loginuser' "); if (is_array($row)) { if (!empty($row['pwd_new']) && !password_verify($loginpwd, $row['pwd_new'])) { + $this->loginError($loginuser); return -1; - }else if (!empty($row['pwd']) && $this->GetShortPwd($row['pwd']) != $this->GetEncodePwd($loginpwd)) { + } else if (!empty($row['pwd']) && $this->GetShortPwd($row['pwd']) != $this->GetEncodePwd($loginpwd)) { + $this->loginError($loginuser); return -1; } else { if (empty($row['pwd_new']) && function_exists('password_hash')) { @@ -413,6 +415,58 @@ class MemberLogin return 0; } } + + /** + * 是否需要验证码 + * + * @param mixed $loginuser + * @return bool + */ + function isNeedCheckCode($loginuser) + { + $num = $this->getLoginError($loginuser); + return $num >= 3 ? true : false; + } + + /** + * 1分钟以内登录错误的次数 + * + * @param mixed $loginuser + * @return int 登录错误次数 + */ + function getLoginError($loginuser) + { + global $dsql; + $rs = CheckUserID($loginuser, '用户名', FALSE); + //用户名不正确时返回验证错误,原登录名通过引用返回错误提示信息 + if ($rs != 'ok') { + return -1; + } + $row = $dsql->GetOne("SELECT loginerr,logintime FROM `#@__member` WHERE userid LIKE '$loginuser'"); + if (is_array($row)) { + //1分钟内如果输错3次则需要验证码 + return (time() - (int)$row['logintime']) < 60 ? (int)$row['loginerr'] : 0; + } else { + return -1; + } + } + /** + * 记录登录错误 + * + * @return void + */ + function loginError($loginuser) + { + global $dsql; + $rs = CheckUserID($loginuser, '用户名', FALSE); + //用户名不正确时返回验证错误,原登录名通过引用返回错误提示信息 + if ($rs != 'ok') { + return; + } + $loginip = GetIP(); + $inquery = "UPDATE `#@__member` SET loginip='$loginip',logintime='" . time() . "',loginerr=loginerr+1 WHERE userid='" . $loginuser . "'"; + $dsql->ExecuteNoneQuery($inquery); + } /** * 保存用户cookie * @@ -431,7 +485,7 @@ class MemberLogin $this->M_ID = $uid; $this->M_LoginTime = time(); $loginip = GetIP(); - $inquery = "UPDATE `#@__member` SET loginip='$loginip',logintime='".$this->M_LoginTime."' WHERE mid='".$uid."'"; + $inquery = "UPDATE `#@__member` SET loginip='$loginip',logintime='".$this->M_LoginTime."',loginerr=0 WHERE mid='".$uid."'"; $dsql->ExecuteNoneQuery($inquery); if ($this->M_KeepTime > 0) { PutCookie('DedeUserID', $uid, $this->M_KeepTime); @@ -445,7 +499,7 @@ class MemberLogin * 获得会员目前的状态 * * @access public - * @param string $dsql 数据库连接 + * @param object $dsql 数据库连接 * @return string */ function GetSta($dsql) diff --git a/src/system/userlogin.class.php b/src/system/userlogin.class.php index b82b9641..d6b1ad6d 100755 --- a/src/system/userlogin.class.php +++ b/src/system/userlogin.class.php @@ -106,10 +106,10 @@ function CheckCatalog($cid, $msg) */ function AddMyAddon($fid, $filename) { - $cacheFile = DEDEDATA.'/cache/addon-'.session_id().'.inc'; + $cacheFile = DEDEDATA . '/cache/addon-' . session_id() . '.inc'; if (!file_exists($cacheFile)) { $fp = fopen($cacheFile, 'w'); - fwrite($fp, '<'.'?php'."\r\n"); + fwrite($fp, '<' . '?php' . "\r\n"); fwrite($fp, "\$myaddons = array();\r\n"); fwrite($fp, "\$maNum = 0;\r\n"); fclose($fp); @@ -133,7 +133,7 @@ function AddMyAddon($fid, $filename) function ClearMyAddon($aid = 0, $title = '') { global $dsql; - $cacheFile = DEDEDATA.'/cache/addon-'.session_id().'.inc'; + $cacheFile = DEDEDATA . '/cache/addon-' . session_id() . '.inc'; $_SESSION['bigfile_info'] = array(); $_SESSION['file_info'] = array(); if (!file_exists($cacheFile)) { @@ -212,16 +212,18 @@ class userLogin $this->userName = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $username); $this->userPwd = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $userpwd); $pwd = substr(md5($this->userPwd), 5, 20); - $dsql->SetQuery("SELECT admin.*,atype.purviews FROM `#@__admin` admin LEFT JOIN `#@__admintype` atype ON atype.`rank`=admin.usertype WHERE admin.userid LIKE '".$this->userName."' LIMIT 0,1"); + $dsql->SetQuery("SELECT admin.*,atype.purviews FROM `#@__admin` admin LEFT JOIN `#@__admintype` atype ON atype.`rank`=admin.usertype WHERE admin.userid LIKE '" . $this->userName . "' LIMIT 0,1"); $dsql->Execute(); $row = $dsql->GetObject(); if (!isset($row->pwd)) { return -1; } else if (!empty($row->pwd_new) && !password_verify($this->userPwd, $row->pwd_new)) { + $this->loginError($row->id); return -2; } else if (!empty($row->pwd) && $pwd != $row->pwd) { + $this->loginError($row->id); return -2; - }else { + } else { $upsql = ""; if (empty($row->pwd_new) && function_exists('password_hash')) { //升级密码 @@ -234,13 +236,58 @@ class userLogin $this->userChannel = $row->typeid; $this->userName = $row->uname; $this->userPurview = $row->purviews; - $inquery = "UPDATE `#@__admin` SET loginip='$loginip',logintime='".time()."'{$upsql} WHERE id='".$row->id."'"; + $inquery = "UPDATE `#@__admin` SET loginip='$loginip',logintime='" . time() . "'{$upsql},loginerr=0 WHERE id='" . $row->id . "'"; $dsql->ExecuteNoneQuery($inquery); - $sql = "UPDATE `#@__member` SET logintime=".time().", loginip='$loginip' WHERE mid=".$row->id; + $sql = "UPDATE `#@__member` SET logintime=" . time() . ", loginip='$loginip' WHERE mid=" . $row->id; $dsql->ExecuteNoneQuery($sql); return 1; } } + + + /** + * 是否需要验证码 + * + * @param mixed $username + * @return bool + */ + function isNeedCheckCode($username) + { + $num = $this->getLoginError($username); + return $num >= 3 ? true : false; + } + + /** + * 1分钟以内登录错误的次数 + * + * @param mixed $username + * @return int 登录错误次数 + */ + function getLoginError($username) + { + global $dsql; + $this->userName = preg_replace("/[^0-9a-zA-Z_@!\.-]/", '', $username); + $row = $dsql->GetOne("SELECT loginerr,logintime FROM `#@__admin` WHERE userid LIKE '$this->userName'"); + if (is_array($row)) { + //1分钟内如果输错3次则需要验证码 + return (time() - (int)$row['logintime']) < 60 ? (int)$row['loginerr'] : 0; + } else { + return -1; + } + } + + /** + * 记录登录错误 + * + * @return void + */ + function loginError($adminid) + { + global $dsql; + $loginip = GetIP(); + $inquery = "UPDATE `#@__admin` SET loginip='$loginip',logintime='" . time() . "',loginerr=loginerr+1 WHERE id='" . $adminid . "'"; + $dsql->ExecuteNoneQuery($inquery); + } /** * 保持用户的会话状态 * @@ -281,7 +328,7 @@ class userLogin function ReWriteAdminChannel() { //$this->userChannel - $cacheFile = DEDEDATA.'/cache/admincat_'.$this->userID.'.inc'; + $cacheFile = DEDEDATA . '/cache/admincat_' . $this->userID . '.inc'; //管理员管理的栏目列表 $typeid = trim($this->userChannel); if (empty($typeid) || $this->getUserType() >= 10) { @@ -296,7 +343,7 @@ class userLogin $typeids = explode(',', $typeid); $typeid = ''; foreach ($typeids as $tid) { - $typeid .= ($typeid == '' ? GetSonIdsUL($tid) : ','.GetSonIdsUL($tid)); + $typeid .= ($typeid == '' ? GetSonIdsUL($tid) : ',' . GetSonIdsUL($tid)); } $typeids = explode(',', $typeid); $typeidsnew = array_unique($typeids); @@ -443,4 +490,3 @@ function GetSonIdsLogicUL($id, $sArr, $channel = 0, $addthis = FALSE) } } } -?> \ No newline at end of file diff --git a/src/theme/dedebiz/foot.htm b/src/theme/dedebiz/foot.htm index 826912e6..293741fa 100644 --- a/src/theme/dedebiz/foot.htm +++ b/src/theme/dedebiz/foot.htm @@ -13,10 +13,10 @@ + @@ -23,8 +24,14 @@ -
+
+
注册
忘记密码