Преглед на файлове

feat:用户权限&登录校验

aiden преди 4 месеца
родител
ревизия
d28aa135b2
променени са 6 файла, в които са добавени 192 реда и са изтрити 142 реда
  1. 107 4
      app/common.php
  2. 14 74
      app/controller/User.php
  3. 67 61
      app/controller/UserRole.php
  4. 1 1
      app/validate/UserValidate.php
  5. 2 1
      composer.json
  6. 1 1
      config/app.php

+ 107 - 4
app/common.php

@@ -1,6 +1,7 @@
 <?php
 
 use Firebase\JWT\JWT;
+use Firebase\JWT\Key;
 
 /// 加密密钥
 $GLOBALS['token_key_secret'] = "z.1i8L?Ld+ovuA4r%4YZrz?w1Y%-NYvlrJ=TqV$[W[5=B#C[=l2gHV8gJ,DhZc";
@@ -35,19 +36,121 @@ if(!function_exists('json_error')){
 }
 
 /**
- * 加密登录数据
+ * 生成JWT Token
  *
- * @param string $data 待加密数据
- * @param string $key 加密密钥
+ * @param array $data 待加密数据
+ * @param int $expire 过期时间(秒),0表示使用默认过期时间
  * @return string
  */
 if(!function_exists('generateToken')){
     function generateToken($data = [], $expire = 0){
         $payload = [
-            'exp' => time() + ($expire > 0 ? $expire : $GLOBALS['cookieExpire']), // 24小时有效期
+            'exp' => time() + ($expire > 0 ? $expire : $GLOBALS['cookieExpire']), // 有效期
+            'iat' => time(), // 签发时间
         ];
         $payload = array_merge($payload, $data);
         $token = JWT::encode($payload, $GLOBALS['token_key_secret'], 'HS256');
         return $token;
     }
+}
+
+/**
+ * 解析JWT Token
+ *
+ * @param string $token JWT Token字符串
+ * @return array|null 解析成功返回payload数组,失败返回null
+ */
+if(!function_exists('parseToken')){
+    function parseToken($token) {
+        try {
+            if (empty($token)) {
+                return null;
+            }
+            
+            // 使用JWT库解析token
+            $decoded = JWT::decode($token, new Key($GLOBALS['token_key_secret'], 'HS256'));
+            
+            // 转换为数组
+            $payload = (array) $decoded;
+            
+            // 检查是否过期
+            if (isset($payload['exp']) && $payload['exp'] < time()) {
+                return null;
+            }
+            
+            return $payload;
+            
+        } catch (\Firebase\JWT\ExpiredException $e) {
+            // Token已过期
+            return null;
+        } catch (\Firebase\JWT\SignatureInvalidException $e) {
+            // 签名无效
+            return null;
+        } catch (\Firebase\JWT\BeforeValidException $e) {
+            // Token尚未生效
+            return null;
+        } catch (\Exception $e) {
+            // 其他异常
+            return null;
+        }
+    }
+}
+
+/**
+ * 验证Token是否有效
+ *
+ * @param string $token JWT Token字符串
+ * @return bool
+ */
+if(!function_exists('verifyToken')){
+    function verifyToken($token) {
+        return parseToken($token) !== null;
+    }
+}
+
+/**
+ * 检查用户登录状态
+ *
+ * @return array|null 登录成功返回用户信息数组,失败返回null
+ */
+if(!function_exists('checkUserLogin')){
+    function checkUserLogin() {
+        $token = \think\facade\Cookie::get('auth_token');
+        if (!$token) {
+            return null;
+        }
+        
+        return parseToken($token);
+    }
+}
+
+/**
+ * 检查用户权限
+ *
+ * @param array $user 用户信息数组
+ * @param string $controller 控制器名称
+ * @param string $action 操作名称
+ * @return bool 有权限返回true,无权限返回false
+ */
+if(!function_exists('checkPermission')){
+    function checkPermission($user, $controller, $action) {
+        // 超级管理员拥有所有权限
+        $superAdminRoleId = \think\facade\Config::get('permission.super_admin_role_id', 1);
+        if ($user['user_role'] == $superAdminRoleId) {
+            return true;
+        }
+        
+        // 获取用户角色权限
+        $role = \app\model\UserRoleModel::getRoleById($user['user_role'], $user['merchant_id']);
+        if (!$role) {
+            return false;
+        }
+        
+        $privileges = $role->privileges;
+        
+        // 检查是否有对应权限
+        return isset($privileges[$controller]) && 
+               is_array($privileges[$controller]) && 
+               in_array($action, $privileges[$controller]);
+    }
 }

+ 14 - 74
app/controller/User.php

@@ -85,13 +85,13 @@ class User extends BaseController
     public function createUser()
     {
         // 获取当前登录用户信息
-        $loginInfo = $this->checkUserLogin();
+        $loginInfo = checkUserLogin();
         if (!$loginInfo) {
             return json_error([], '请先登录');
         }
         
         // 检查是否有创建用户权限
-        if (!$this->checkPermission($loginInfo, 'user', 'create')) {
+        if (!checkPermission($loginInfo, 'user', 'create')) {
             return json_error([], '没有创建用户的权限');
         }
 
@@ -138,12 +138,12 @@ class User extends BaseController
      */
     public function list()
     {
-        $loginInfo = $this->checkUserLogin();
+        $loginInfo = checkUserLogin();
         if (!$loginInfo) {
             return json_error([], '请先登录');
         }
         
-        if (!$this->checkPermission($loginInfo, 'user', 'list')) {
+        if (!checkPermission($loginInfo, 'user', 'list')) {
             return json_error([], '没有查看用户列表的权限');
         }
         
@@ -204,16 +204,16 @@ class User extends BaseController
      */
     public function detail()
     {
-        $loginInfo = $this->checkUserLogin();
+        $loginInfo = checkUserLogin();
         if (!$loginInfo) {
             return json_error([], '请先登录');
         }
         
-        if (!$this->checkPermission($loginInfo, 'user', 'detail')) {
+        if (!checkPermission($loginInfo, 'user', 'detail')) {
             return json_error([], '没有查看用户详情的权限');
         }
         
-        $userId = $this->request->param('user_id', 0, 'intval');
+        $userId = Request::param('user_id', 0, 'intval');
         if (!$userId) {
             return json_error([], '用户ID不能为空');
         }
@@ -245,16 +245,16 @@ class User extends BaseController
      */
     public function update()
     {
-        $loginInfo = $this->checkUserLogin();
+        $loginInfo = checkUserLogin();
         if (!$loginInfo) {
             return json_error([], '请先登录');
         }
         
-        if (!$this->checkPermission($loginInfo, 'user', 'update')) {
+        if (!checkPermission($loginInfo, 'user', 'update')) {
             return json_error([], '没有编辑用户的权限');
         }
         
-        $userId = $this->request->post('user_id', 0, 'intval');
+        $userId = Request::post('user_id', 0, 'intval');
         if (!$userId) {
             return json_error([], '用户ID不能为空');
         }
@@ -268,7 +268,7 @@ class User extends BaseController
         }
         
         // 获取更新数据
-        $data = $this->request->only([
+        $data = Request::only([
             'nick_name', 'phone', 'password', 'user_role', 'white_list_ip'
         ]);
         
@@ -307,16 +307,16 @@ class User extends BaseController
      */
     public function delete()
     {
-        $loginInfo = $this->checkUserLogin();
+        $loginInfo = checkUserLogin();
         if (!$loginInfo) {
             return json_error([], '请先登录');
         }
         
-        if (!$this->checkPermission($loginInfo, 'user', 'delete')) {
+        if (!checkPermission($loginInfo, 'user', 'delete')) {
             return json_error([], '没有删除用户的权限');
         }
         
-        $userId = $this->request->post('user_id', 0, 'intval');
+        $userId = Request::post('user_id', 0, 'intval');
         if (!$userId) {
             return json_error([], '用户ID不能为空');
         }
@@ -341,66 +341,6 @@ class User extends BaseController
         }
     }
     
-    /**
-     * 获取当前登录用户信息
-     */
-    private function checkUserLogin()
-    {
-        $token = Cookie::get('auth_token');
-        if (!$token) {
-            return null;
-        }
-        
-        return $this->verifyToken($token);
-    }
-    
-    /**
-     * 验证Token
-     */
-    private function verifyToken($token)
-    {
-        try {
-            $parts = explode('.', $token);
-            if (count($parts) != 3) {
-                return null;
-            }
-            
-            $payload = json_decode(base64_decode($parts[1]), true);
-            
-            if ($payload['exp'] < time()) {
-                return null;
-            }
-            
-            return $payload;
-        } catch (\Exception $e) {
-            return null;
-        }
-    }
-    
-    /**
-     * 检查权限
-     */
-    private function checkPermission($user, $controller, $action)
-    {
-        // 超级管理员拥有所有权限
-        $superAdminRoleId = Config::get('permission.super_admin_role_id', 1);
-        if ($user['user_role'] == $superAdminRoleId) {
-            return true;
-        }
-        
-        // 获取用户角色权限
-        $role = UserRoleModel::getRoleById($user['user_role'], $user['merchant_id']);
-        if (!$role) {
-            return false;
-        }
-        
-        $privileges = $role->privileges;
-        
-        // 检查是否有对应权限
-        return isset($privileges[$controller]) && 
-               is_array($privileges[$controller]) && 
-               in_array($action, $privileges[$controller]);
-    }
 
     /**
      * 验证输入数据

+ 67 - 61
app/controller/UserRole.php

@@ -8,6 +8,7 @@ use app\model\UserRoleModel;
 use app\model\UserModel;
 use think\facade\Config;
 use think\facade\Request;
+use think\facade\Cookie;
 
 class UserRole extends BaseController
 {
@@ -16,6 +17,15 @@ class UserRole extends BaseController
      */
     public function getPermissions()
     {
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'permissions')) {
+            return json_error([], '没有查看权限配置的权限');
+        }
+        
         $permissions = Config::get('permission.permissions', []);
         return json_success($permissions, '获取权限配置成功');
     }
@@ -25,13 +35,21 @@ class UserRole extends BaseController
      */
     public function list()
     {
-        $merchantId = $this->getMerchantId();
-        $list = UserRoleModel::getRoleList($merchantId);
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'list')) {
+            return json_error([], '没有查看角色列表的权限');
+        }
+        
+        $list = UserRoleModel::getRoleList($loginInfo['merchant_id']);
         
         return json_success([
             'list' => $list,
             'total' => count($list)
-        ]);
+        ], '获取角色列表成功');
     }
     
     /**
@@ -39,19 +57,26 @@ class UserRole extends BaseController
      */
     public function detail()
     {
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'detail')) {
+            return json_error([], '没有查看角色详情的权限');
+        }
+        
         $id = $this->request->param('id', 0, 'intval');
         if (!$id) {
             return json_error([], '角色ID不能为空');
         }
         
-        $merchantId = $this->getMerchantId();
-        
-        $role = UserRoleModel::getRoleById($id, $merchantId);
+        $role = UserRoleModel::getRoleById($id, $loginInfo['merchant_id']);
         if (!$role) {
             return json_error([], '角色不存在');
         }
         
-        return json_success($role);
+        return json_success($role, '获取角色详情成功');
     }
     
     /**
@@ -59,6 +84,15 @@ class UserRole extends BaseController
      */
     public function create()
     {
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'create')) {
+            return json_error([], '没有创建角色的权限');
+        }
+        
         $data = Request::only(['role_name', 'privileges']);
         
         if (empty($data['role_name'])) {
@@ -69,13 +103,11 @@ class UserRole extends BaseController
             return json_error([], '权限配置不能为空');
         }
         
-        $merchantId = $this->getMerchantId();
-        
-        if (UserRoleModel::checkRoleExists($data['role_name'], $merchantId)) {
+        if (UserRoleModel::checkRoleExists($data['role_name'], $loginInfo['merchant_id'])) {
             return json_error([], '角色名称已存在');
         }
         
-        $data['merchant_id'] = $merchantId;
+        $data['merchant_id'] = $loginInfo['merchant_id'];
         
         try {
             $role = UserRoleModel::createRole($data);
@@ -90,6 +122,15 @@ class UserRole extends BaseController
      */
     public function update()
     {
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'update')) {
+            return json_error([], '没有编辑角色的权限');
+        }
+        
         $id = Request::param('id', 0, 'intval');
         if (!$id) {
             return json_error([], '角色ID不能为空');
@@ -105,19 +146,17 @@ class UserRole extends BaseController
             return json_error([], '权限配置不能为空');
         }
         
-        $merchantId = $this->getMerchantId();
-        
-        $role = UserRoleModel::getRoleById($id, $merchantId);
+        $role = UserRoleModel::getRoleById($id, $loginInfo['merchant_id']);
         if (!$role) {
             return json_error([], '角色不存在');
         }
         
-        if (UserRoleModel::checkRoleExists($data['role_name'], $merchantId, $id)) {
+        if (UserRoleModel::checkRoleExists($data['role_name'], $loginInfo['merchant_id'], $id)) {
             return json_error([], '角色名称已存在');
         }
         
         try {
-            UserRoleModel::updateRole($id, $merchantId, $data);
+            UserRoleModel::updateRole($id, $loginInfo['merchant_id'], $data);
             return json_success([], '更新角色成功');
         } catch (\Exception $e) {
             return json_error([], '更新角色失败:' . $e->getMessage());
@@ -129,14 +168,21 @@ class UserRole extends BaseController
      */
     public function delete()
     {
+        $loginInfo = checkUserLogin();
+        if (!$loginInfo) {
+            return json_error([], '请先登录');
+        }
+        
+        if (!checkPermission($loginInfo, 'role', 'delete')) {
+            return json_error([], '没有删除角色的权限');
+        }
+        
         $id = Request::param('id', 0, 'intval');
         if (!$id) {
             return json_error([], '角色ID不能为空');
         }
         
-        $merchantId = $this->getMerchantId();
-        
-        $role = UserRoleModel::getRoleById($id, $merchantId);
+        $role = UserRoleModel::getRoleById($id, $loginInfo['merchant_id']);
         if (!$role) {
             return json_error([], '角色不存在');
         }
@@ -147,58 +193,18 @@ class UserRole extends BaseController
         }
         
         $userCount = UserModel::where('user_role', $id)
-            ->where('merchant_id', $merchantId)
+            ->where('merchant_id', $loginInfo['merchant_id'])
             ->count();
         if ($userCount > 0) {
             return json_error([], '该角色下还有用户,不能删除');
         }
         
         try {
-            UserRoleModel::deleteRole($id, $merchantId);
+            UserRoleModel::deleteRole($id, $loginInfo['merchant_id']);
             return json_success([], '删除角色成功');
         } catch (\Exception $e) {
             return json_error([], '删除角色失败:' . $e->getMessage());
         }
     }
     
-    /**
-     * 获取商户ID
-     */
-    private function getMerchantId()
-    {
-        $token = Request::cookie('auth_token');
-        if (!$token) {
-            throw new \Exception('未登录');
-        }
-        
-        $payload = $this->verifyToken($token);
-        if (!$payload) {
-            throw new \Exception('登录已过期');
-        }
-        
-        return $payload['merchant_id'] ?? 0;
-    }
-    
-    /**
-     * 验证Token
-     */
-    private function verifyToken($token)
-    {
-        try {
-            $parts = explode('.', $token);
-            if (count($parts) != 3) {
-                return false;
-            }
-            
-            $payload = json_decode(base64_decode($parts[1]), true);
-            
-            if ($payload['exp'] < time()) {
-                return false;
-            }
-            
-            return $payload;
-        } catch (\Exception $e) {
-            return false;
-        }
-    }
 }

+ 1 - 1
app/validate/UserValidate.php

@@ -25,7 +25,7 @@ class UserValidate extends Validate
         'user_name.regex'    => '用户名只能包含字母或数字,以字母开头,长度在6到20个字符之间',
         'user_name.unique'   => '用户名已存在',
         'password.require'   => '密码不能为空',
-        'password.length'    => '密码只能包含字母、数字及特殊字符(_+@%), 长度在6-20个字符之间',
+        'password.regex'    => '密码只能包含字母、数字及特殊字符(_+@%), 长度在6-20个字符之间',
         'nickname.require'   => '昵称不能为空',
         'nickname.chsDash'   => '昵称只能包含汉字、字母及数字,长度在2-20个字符之间',
         'user_role.integer'  => '角色ID必须是整数',

+ 2 - 1
composer.json

@@ -23,7 +23,8 @@
         "php": ">=8.0.0",
         "topthink/framework": "^8.0",
         "topthink/think-orm": "^3.0|^4.0",
-        "topthink/think-filesystem": "^2.0|^3.0"
+        "topthink/think-filesystem": "^2.0|^3.0",
+        "firebase/php-jwt": "^6.11"
     },
     "require-dev": {
         "topthink/think-dumper": "^1.0",

+ 1 - 1
config/app.php

@@ -26,5 +26,5 @@ return [
     // 错误显示信息,非调试模式有效
     'error_message'    => '页面错误!请稍后再试~',
     // 显示错误信息
-    'show_error_msg'   => false,
+    'show_error_msg'   => true,
 ];