yzx 7 months ago
parent
commit
9377be7a7f

+ 2 - 3
app/acctconnect/controller/Connect.php

@@ -27,14 +27,13 @@ class Connect extends BaseController{
     public function index(){
         if (request()->isAjax()) {
             $param = get_params();
-            // $session_admin = get_config('app.session_admin');
-            // $id = Session::get($session_admin)['id'];
+//            $session_admin = get_config('app.session_admin');
+//            $id = Session::get($session_admin)['id'];
             $id = get_login_admin('id');
             if($id == ''){
                 return to_assign(1, '登录过期,请重新登录!');
             }
             $acct_connect = Db::name('Admin')->where('id', $id)->value('acct_connect');
-
             $where = array();
             $where[] = ['status', '>=', 0];
 

+ 89 - 82
app/admin/controller/Admin.php

@@ -46,18 +46,18 @@ class Admin extends BaseController
             $admin_permission = Db::name('admin')->where('id', $id)->value('permission');
             // halt($unit_name);
             $param = get_params();
-            
+
             if (!empty($param['keywords'])) {
                 $where[] = ['id|username|nickname|desc|mobile', 'like', '%' . $param['keywords'] . '%'];
             }
-            
+
             $where = array();
             $permission = array();
             $where[] = ['status', '>=', 0];
             if($admin_permission == 0){
                 $permission[] = ['unit_name', '=',$unit_name];
             }
-            
+
             $rows = empty($param['limit']) ? get_config('app.page_size') : $param['limit'];
             $admin = AdminList::where($where)->with('Department')
                 ->where($permission)
@@ -80,13 +80,16 @@ class Admin extends BaseController
             return view();
         }
     }
-    
+
 
     //添加
     public function add()
-    {	
-		if (request()->isAjax()) {
-			$param = get_params();
+    {
+        if (request()->isAjax()) {
+            $param = get_params();
+            if (!preg_match('/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $param['pwd'])) {
+                return to_assign(1, '密码必须至少包含8个字符,含有大小写字母、数字和特殊字符!');
+            }
             // halt($param);
             if (!empty($param['id']) && $param['id'] > 0) { //对已存在账号的编辑
                 try {
@@ -100,7 +103,7 @@ class Admin extends BaseController
                     if (empty($param['edit_pwd_confirm']) or $param['edit_pwd_confirm'] !== $param['edit_pwd']) {
                         return to_assign(1, '两次密码不一致');
                     }
-                    
+
                     $param['salt'] = set_salt(20);
                     $param['pwd'] = set_password($param['edit_pwd'], $param['salt']);
                 }
@@ -109,6 +112,7 @@ class Admin extends BaseController
                 Db::startTrans();
                 try {
                     // halt($param);
+                    $param['last_password_change'] = time();
                     Db::name('Admin')->where(['id' => $param['id']])->strict(false)->field(true)->update($param);   //更新密码
                     Db::name('AdminGroupAccess')->where(['uid' => $param['id']])->delete();     //先删除权限组
                     foreach ($param['group_id'] as $k => $v) {
@@ -128,14 +132,14 @@ class Admin extends BaseController
                         $char = mb_substr($param['nickname'], 0, 1, 'utf-8');
                         Db::name('Admin')->where('id', $param['id'])->update(['thumb' => $this->to_avatars($char)]);
                     }
-                    // 
+                    //
                     if($param['is_principal'] == 1){
-                        
+
                         // $res = Db::name('Department')->where('id', $param['did'])->value('leader_id');
                         // halt($res);
                         $res = Db::name('Department')->where('id', $param['did'])->update(['leader_id' => $param['id']]);
                         // $this->Department->where('id', $param['did'])->force()->save(['leader_id' => $param['id']]);
-                        
+
                         // halt($res);
                     }
 
@@ -172,10 +176,12 @@ class Admin extends BaseController
                 }
                 $param['salt'] = set_salt(20);
                 $param['pwd'] = set_password($param['pwd'], $param['salt']);
+                $param['last_password_change'] = time();
+
                 // 启动事务
                 Db::startTrans();
                 try {
-                    
+
                     foreach ($param['group_id'] as $k => $v) {
                         $param['admin_group_id'] = $v;
                     }
@@ -197,6 +203,7 @@ class Admin extends BaseController
                             'group_id' => $v,
                         ];
                     }
+
                     Db::name('AdminGroupAccess')->strict(false)->field(true)->insertAll($data);
                     if (!isset($param['thumb']) || $param['thumb'] == '') {
                         $char = mb_substr($param['nickname'], 0, 1, 'utf-8');
@@ -224,9 +231,9 @@ class Admin extends BaseController
                 }
             }
             return to_assign(0,"操作成功");
-		}else{
-		    
-			$id = empty(get_params('id')) ? 0 : get_params('id');
+        }else{
+
+            $id = empty(get_params('id')) ? 0 : get_params('id');
             // dump($id);
             $permission = Db::name('admin')->where('id', get_login_admin('id'))->value('permission');
             $unit_name = Db::name('admin')->where('id', get_login_admin('id'))->value('unit_name');
@@ -243,22 +250,22 @@ class Admin extends BaseController
 
                 ];
             }
-            
+
 
             $department = Db::name('Department')
-                    ->where('status', '>=', 0)
-                    ->where($where_d)
-                    ->select()
-                    ->toArray();
+                ->where('status', '>=', 0)
+                ->where($where_d)
+                ->select()
+                ->toArray();
             // dump($department);
             $department = set_recursion($department);
             // dump($department);
             $position = Db::name('Position')
-                    ->where('status', '>=', 0)
-                    ->where($where_p)
-                    ->order('create_time asc')
-                    ->select()
-                    ->toArray();
+                ->where('status', '>=', 0)
+                ->where($where_p)
+                ->order('create_time asc')
+                ->select()
+                ->toArray();
 
             foreach($position as $key => $value){
 
@@ -267,29 +274,29 @@ class Admin extends BaseController
                 $position[$key]['did_title'] = $dep;
             }
 
-            
+
             $group = Db::name('AdminGroup')
-                    ->where($where_g)
-                    ->select()->toarray();
-                    
+                ->where($where_g)
+                ->select()->toarray();
+
             if($permission == 1){
                 $group = Db::name('AdminGroup')
                     ->where('unit_name', '=', $unit_name)
                     ->select()->toarray();
-                    // dump($group);
+                // dump($group);
             }
-            
+
             $group_mine = Db::name('AdminGroup')->where('id', $group_id)->select()->toArray();
             // dump($permission);
             if(get_login_admin('user_type') == -1){
                 unset($group[0]);   //移除超管权限组
             }
-            
+
             $group = array_merge($group_mine, $group);
-            
-			if ($id > 0) {
-				$admin = get_admin(get_params('id'));
-				// dump($admin);
+
+            if ($id > 0) {
+                $admin = get_admin(get_params('id'));
+                // dump($admin);
                 // $did = get_login_admin('did');
                 $leader_id = Db::name('Department')->where('id', $admin['did'])->value('leader_id');
                 // dump($leader_id);
@@ -298,19 +305,19 @@ class Admin extends BaseController
                 }else{
                     $is_principal = 0;
                 }
-                
+
                 View::assign('is_principal', $is_principal);
-				View::assign('admin', $admin);
-			}
+                View::assign('admin', $admin);
+            }
             // dump($group);
             // dump($department);
             View::assign('permission', $permission);
-			View::assign('department', $department);
+            View::assign('department', $department);
             View::assign('position', $position);
             View::assign('group', $group);
-			View::assign('id', $id);
-			return view();
-		}
+            View::assign('id', $id);
+            return view();
+        }
     }
 
     public function to_avatars($char)
@@ -366,35 +373,35 @@ class Admin extends BaseController
     //查看
     public function view()
     {
-		$id = get_params('id');
-		$rule = get_admin_rule();
-
-		$user_groups = Db::name('AdminGroupAccess')
-                ->alias('a')
-                ->join("AdminGroup g", "a.group_id=g.id", 'LEFT')
-                ->where("a.uid='{$id}' and g.status='1'")
-                ->select()
-                ->toArray();
-		$groups = $user_groups ?: [];
-
-		$rules = [];
-		foreach ($groups as $g) {
-			$rules = array_merge($rules, explode(',', trim($g['rules'], ',')));
-		}
-		$rules = array_unique($rules);
+        $id = get_params('id');
+        $rule = get_admin_rule();
+
+        $user_groups = Db::name('AdminGroupAccess')
+            ->alias('a')
+            ->join("AdminGroup g", "a.group_id=g.id", 'LEFT')
+            ->where("a.uid='{$id}' and g.status='1'")
+            ->select()
+            ->toArray();
+        $groups = $user_groups ?: [];
+
+        $rules = [];
+        foreach ($groups as $g) {
+            $rules = array_merge($rules, explode(',', trim($g['rules'], ',')));
+        }
+        $rules = array_unique($rules);
 
-		$role_rule = create_tree_list(0, $rule, $rules);
+        $role_rule = create_tree_list(0, $rule, $rules);
 
         $role_rule = $this->Role->remove_checked_false($role_rule);
 
-		$department = get_department();
+        $department = get_department();
         // dump($department);
         $position = Db::name('Position')->where('status', '>=', 0)->order('create_time asc')->select();
-		View::assign('department', $department);
+        View::assign('department', $department);
         View::assign('position', $position);
         View::assign('role_rule', $role_rule);
-        View::assign('admin', get_admin($id));		
-		add_log('view', get_params('id'));
+        View::assign('admin', get_admin($id));
+        add_log('view', get_params('id'));
         return view('', ['admin' => get_admin(get_params('id'))]);
     }
     //删除
@@ -440,19 +447,19 @@ class Admin extends BaseController
             foreach ($content as $k => $v) {
                 $data = $v;
                 $param_array = json_decode($v['param'], true);
-				if(is_array($param_array)){
-					$param_value = '';
-					foreach ($param_array as $key => $value) {
-						if (is_array($value)) {
-							$value = implode(',', $value);
-						}
-						$param_value .= $key . ':' . $value . '  |  ';
-					}
-					$data['param'] = $param_value;
-				}
-				else{
-					$data['param'] = $param_array;
-				}
+                if(is_array($param_array)){
+                    $param_value = '';
+                    foreach ($param_array as $key => $value) {
+                        if (is_array($value)) {
+                            $value = implode(',', $value);
+                        }
+                        $param_value .= $key . ':' . $value . '  |  ';
+                    }
+                    $data['param'] = $param_value;
+                }
+                else{
+                    $data['param'] = $param_array;
+                }
                 $content->offsetSet($k, $data);
             }
             return table_assign(0, '', $content);
@@ -467,17 +474,17 @@ class Admin extends BaseController
         $did = Db::name('Admin')->where('id', $id)->value('did');
 
         $pid = $did;
-        
-        while($pid != 0){   
+
+        while($pid != 0){
 
             $value = Db::name('department')->where('id', $pid)->column('id,pid,title')[0];
             $id = $value['id'];
             $pid = $value['pid'];
-            $title = $value['title'];  
+            $title = $value['title'];
         }
-        
+
         // halt($value);
         return $id;
     }
-    
+
 }

+ 7 - 0
app/admin/controller/Api.php

@@ -270,6 +270,7 @@ class Api extends BaseController
     {
         if (request()->isAjax()) {
             $param = get_params();
+//            halt($param);
             try {
                 validate(AdminCheck::class)->scene('editpwd')->check($param);
             } catch (ValidateException $e) {
@@ -280,9 +281,15 @@ class Api extends BaseController
             if (set_password($param['old_pwd'], $admin['salt']) !== $admin['pwd']) {
                 return to_assign(1, '旧密码不正确!');
             }
+
+            if (!preg_match('/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $param['pwd'])) {
+                return to_assign(1, '密码必须至少包含8个字符,含有大小写字母、数字和特殊字符!');
+            }
+
             unset($param['username']);
             $param['salt'] = set_salt(20);
             $param['pwd'] = set_password($param['pwd'], $param['salt']);
+            $param['last_password_change'] = time();
             Db::name('Admin')->where([
                 'id' => $admin['id'],
             ])->strict(false)->field(true)->update($param);

+ 32 - 7
app/admin/controller/Login.php

@@ -21,7 +21,10 @@ class Login
     {
         return View();
     }
-	
+    private $loginAttempts = [];
+    private $maxAttempts = 5;
+    private $lockDuration = 600; // 10 minutes
+
     //提交登录
     public function login_submit()
     {
@@ -34,17 +37,32 @@ class Login
             return to_assign(1, $e->getError());
         }
 
+        $ip = request()->ip();
+
+        if (isset($this->loginAttempts[$ip])) {
+            if ($this->loginAttempts[$ip]['count'] >= $this->maxAttempts &&
+                time() - $this->loginAttempts[$ip]['last_attempt'] < $this->lockDuration) {
+                return to_assign(1, '登录尝试次数过多,请稍后再试');
+            } elseif (time() - $this->loginAttempts[$ip]['last_attempt'] >= $this->lockDuration) {
+                $this->loginAttempts[$ip]['count'] = 0;
+            }
+        }
+
         $admin = Db::name('Admin')->where(['username' => $param['username']])->find();
         if (empty($admin)) {
+            $this->recordFailedAttempt($ip);
             return to_assign(1, '用户名或密码错误');
         }
         $param['pwd'] = set_password($param['password'], $admin['salt']);
         if ($admin['pwd'] !== $param['pwd']) {
+            $this->recordFailedAttempt($ip);
             return to_assign(1, '用户名或密码错误');
         }
-        // if ($admin['status'] !== 1) {
-        //     return to_assign(1, '该用户禁止登录,请于系统所有者联系');
-        // }
+
+        if ($admin['status'] !== 1) {
+            return to_assign(1, '该用户禁止登录,请于系统所有者联系');
+        }
+
         $data = [
             'last_login_time' => time(),
             'last_login_ip' => request()->ip(),
@@ -52,16 +70,23 @@ class Login
         ];
         Db::name('admin')->where(['id' => $admin['id']])->update($data);
         $session_admin = get_config('app.session_admin');   // gougu_admin
-    
+
         Session::set($session_admin, $admin);   // null
         $token = make_token();
         set_cache($token, $admin, 7200);
         $admin['token'] = $token;
         add_log('login', $admin['id'], $data);//添加登录日志
-        
+
         return to_assign(0, '登录成功', ['uid' => $admin['id']]);
     }
-
+    private function recordFailedAttempt($ip) {
+        if (!isset($this->loginAttempts[$ip])) {
+            $this->loginAttempts[$ip] = ['count' => 0, 'last_attempt' => 0];
+//            halt($this->loginAttempts[$ip]);
+        }
+        $this->loginAttempts[$ip]['count']++;
+        $this->loginAttempts[$ip]['last_attempt'] = time();
+    }
     //退出登录
     public function login_out()
     {

+ 15 - 0
app/admin/middleware/Auth.php

@@ -92,9 +92,11 @@ class Auth
             redirect('/admin/index/index.html')->send();
             exit;
         }
+
         //验证用户登录
         if ($action !== 'login') {
             $session_admin = get_config('app.session_admin');
+
             if (!Session::has($session_admin)) {
                 if ($request->isAjax()) {
                     return to_assign(404, '请先登录');
@@ -103,7 +105,20 @@ class Auth
                     exit;
                 }
             }
+
+
             $uid = Session::get($session_admin)['id'];
+
+//            halt($uid);
+            // 检查上次密码更换时间
+            $lastPasswordChange = Db::name('Admin')->where('id', $uid)->value('last_password_change');
+
+            if ($lastPasswordChange) {
+                $daysSinceLastChange = (time() - strtotime($lastPasswordChange)) / (60 * 60 * 24);
+                if ($daysSinceLastChange > 180) {
+                    $this->apiError('您的密码已超过180天未更换,请重置密码后再登录。');
+                }
+            }
             //验证用户访问权限
             // if ($action !== 'index' && $action !== 'api') {
             //     if (!$this->checkAuth($controller, $pathInfo, $action, $uid)) {

+ 35 - 1
app/api/controller/Index.php

@@ -23,6 +23,10 @@ class Index extends BaseController
 	protected $middleware = [
     	Auth::class => ['except' 	=> ['index','reg','login'] ]
     ];
+
+    private $loginAttempts = [];
+    private $maxAttempts = 5;
+    private $lockDuration = 600; // 10 minutes
 	
     /**
      * @param $user_id
@@ -101,18 +105,35 @@ class Index extends BaseController
 		if(empty($param['username']) || empty($param['password'])){
 			$this->apiError('参数错误');
 		}
+
+        $ip = request()->ip(); 
+        if (isset($this->loginAttempts[$ip])) {
+            if ($this->loginAttempts[$ip]['count'] >= $this->maxAttempts &&
+                time() - $this->loginAttempts[$ip]['last_attempt'] < $this->lockDuration) {
+                $this->apiError('登录尝试次数过多,请稍后再试');
+            } elseif (time() - $this->loginAttempts[$ip]['last_attempt'] >= $this->lockDuration) {
+                $this->loginAttempts[$ip]['count'] = 0;
+            }
+        }
+
         // 校验用户名密码
 		$user = Db::name('User')->where(['username' => $param['username']])->find();
         if (empty($user)) {
+            $this->recordFailedAttempt($ip);
             $this->apiError('帐号或密码错误');
         }
         $param['pwd'] = set_password($param['password'], $user['salt']);
         if ($param['pwd'] !== $user['password']) {
+            $this->recordFailedAttempt($ip);
             $this->apiError('帐号或密码错误');
         }
         if ($user['status'] == -1) {
             $this->apiError('该用户禁止登录,请于平台联系');
         }
+
+        // Reset failed attempts on successful login
+        $this->loginAttempts[$ip]['count'] = 0;
+
         $data = [
             'last_login_time' => time(),
             'last_login_ip' => request()->ip(),
@@ -125,7 +146,13 @@ class Index extends BaseController
             $this->apiSuccess('登录成功', ['token' => $token]);
         }
     }
-
+    private function recordFailedAttempt($ip) {
+        if (!isset($this->loginAttempts[$ip])) {
+            $this->loginAttempts[$ip] = ['count' => 0, 'last_attempt' => 0];
+        }
+        $this->loginAttempts[$ip]['count']++;
+        $this->loginAttempts[$ip]['last_attempt'] = time();
+    }
     /**
      * @api {post} /index/reg 会员注册
      * @apiDescription  系统注册接口,返回是否成功的提示,需再次登录
@@ -148,8 +175,15 @@ class Index extends BaseController
         if (!empty($user)) {
 			$this->apiError('该账户已经存在');
         }
+
+        // Check password strength
+        if (!preg_match('/^(?=.*[A-Z])(?=.*[a-z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/', $param['pwd'])) {
+            $this->apiError('密码必须至少包含8个字符,含有大小写字母、数字和特殊字符');
+        }
+
         $param['salt'] = set_salt(20);
         $param['password'] = set_password($param['pwd'], $param['salt']);
+
         $param['register_time'] = time();
         $param['headimgurl'] = '';
         $param['register_ip'] = request()->ip();

+ 2 - 0
app/api/middleware/Auth.php

@@ -21,7 +21,9 @@ class Auth
             if (count(explode('.', $token)) != 3) {
                 return json(['code'=>404,'msg'=>'非法请求']);
             }
+
 			$config = get_system_config('token');
+
 			//var_dump($config);exit;
             try {
 				JWT::$leeway = 60;//当前时间减去60,把时间留点余地