request->param(); // 1. 先验证租户名称是否传入(新增:必须传租户名称) try { $this->validate($data, [ 'tenant_name|租户名称' => 'require|length:1,128', // 匹配租户表tenant字段长度 'account|账号' => 'require|length:3,32', 'password|密码' => 'require|length:6,32' ]); } catch (ValidateException $e) { $this->logFail('登录管理', '登录', $e->getMessage()); return json([ 'code' => 400, 'msg' => $e->getError() ]); } // 2. 处理账号兼容(邮箱/手机号转account) if (isset($data['email'])) { $data['account'] = $data['email']; } elseif (isset($data['phone'])) { $data['account'] = $data['phone']; } // 3. 查询租户ID(新增:只查正常状态的租户 status=1) $tenant = Tenant::where('tenant_name', $data['tenant_name']) ->where('status', 1) // 过滤停用/删除的租户 ->field(['id', 'tenant_name']) // 只查需要的字段,提升性能 ->find(); // ThinkPHP 使用 find() // 4. 验证租户是否存在 if (!$tenant) { $this->logFail('登录管理', '登录', '租户不存在或已禁用,租户名称:' . $data['tenant_name']); return json([ 'code' => 401, 'msg' => '租户不存在或已禁用' ]); } $tid = $tenant->id; $tenant_name = $tenant->tenant_name; // 5. 查询用户(新增:关联租户ID,确保用户属于该租户) $user = AdminUser::where('account', $data['account']) ->where('tid', $tid) // 核心:验证用户所属租户 ->where('status', 1) ->find(); // 6. 验证用户是否存在 if (!$user) { $this->logFail('登录管理', '登录', '账号不存在/已禁用,或不属于当前租户,账号:' . $data['account'] . ',租户:' . $tenant_name); return json([ 'code' => 401, 'msg' => '账号不存在或已禁用,或不属于当前租户' ]); } // 7. 验证密码 if (md5($data['password']) !== $user['password']) { $this->logFail('登录管理', '登录', '密码错误,账号:' . $data['account'] . ',租户:' . $tenant_name); return json([ 'code' => 401, 'msg' => '密码错误' ]); } // 8. 更新登录次数和IP try { $loginCount = isset($user['login_count']) && $user['login_count'] !== null ? (int)$user['login_count'] : 0; AdminUser::where('id', $user['id'])->update([ 'login_count' => $loginCount + 1, 'last_login_ip' => $this->request->ip(), 'last_login_time' => date('Y-m-d H:i:s') // 新增:记录最后登录时间,更实用 ]); } catch (\Exception $e) { error_log('更新登录信息失败: ' . $e->getMessage()); } // 9. 组装用户信息(新增:加入租户ID和租户名称和角色权限) $userInfo = [ 'id' => $user['id'], 'account' => $user['account'], 'name' => $user['name'], 'group_id' => $user['group_id'], 'tid' => $tid, // 新增:租户ID 'tenant' => $tenant // 新增:租户名称 ]; // 获取角色权限 if ($user['group_id']) { $userGroup = AdminUserGroup::where('id', $user['group_id'])->find(); if ($userGroup && $userGroup->rights) { $userInfo['rights'] = json_decode($userGroup->rights, true); } } // 10. 生成Token(Token中已包含租户信息,后续可通过Token解析获取) try { $token = $this->generateToken($userInfo); } catch (\Exception $e) { $this->logFail('登录管理', '登录', 'Token生成失败: ' . $e->getMessage()); return json([ 'code' => 500, 'msg' => '登录失败,请稍后重试' ]); } // 11. 写入用户数据缓存(核心:缓存包含租户信息,示例用Redis,可根据你的缓存工具调整) try { $cacheKey = 'admin_user_' . $user['id'] . '_' . $tid; // 缓存键加入租户ID,避免多租户冲突 $cacheExpire = 86400 * 7; // 缓存7天,可根据需求调整 // 写入缓存(这里假设你使用thinkphp的Cache类,若用其他工具可替换) \think\facade\Cache::set($cacheKey, $userInfo, $cacheExpire); } catch (\Exception $e) { error_log('用户缓存写入失败: ' . $e->getMessage()); // 缓存写入失败不影响登录,但记录日志 } // 12. 记录登录成功日志 try { $this->logSuccess('登录管理', '登录', [ 'id' => $user['id'], 'tid' => $tid, 'tenant' => $tenant ], $userInfo); } catch (\Exception $e) { error_log('登录日志记录失败: ' . $e->getMessage()); } // 13. 返回登录结果(包含租户信息) return json([ 'code' => 200, 'msg' => '登录成功', 'data' => [ 'token' => $token, 'user' => $userInfo // 前端可直接获取租户ID和名称 ] ]); } catch (\Exception $e) { $errorMsg = $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine(); error_log('登录失败: ' . $errorMsg); try { $this->logFail('登录管理', '登录', $errorMsg); } catch (\Exception $logError) { error_log('记录登录失败日志也失败: ' . $logError->getMessage()); } return json([ 'code' => 500, 'msg' => '登录失败:' . $e->getMessage() ]); } } /** * 退出登录 * @return Json */ public function logout(): Json { $authHeader = $this->request->header('Authorization', ''); $userInfo = null; if (preg_match('/Bearer\s+(.+)/i', $authHeader, $matches)) { $tokenData = $this->verifyToken($matches[1]); if ($tokenData && isset($tokenData['user'])) { $userInfo = (array)$tokenData['user']; } } if ($userInfo && isset($userInfo['id'])) { $this->logSuccess('登录管理', '退出登录', ['result' => 'success'], $userInfo); } else { OperationLog::create([ 'user_id' => 0, 'user_account' => '', 'user_name' => '未知用户', 'module' => '登录管理', 'action' => '退出登录', 'method' => 'POST', 'url' => $this->request->url(true), 'ip' => $this->request->ip(), 'user_agent' => $this->request->header('user-agent', ''), 'request_data' => null, 'response_data' => json_encode(['result' => 'success'], JSON_UNESCAPED_UNICODE), 'status' => 1, 'error_message' => '', 'execution_time' => 0.0, ]); } return json([ 'code' => 200, 'msg' => '退出成功' ]); } /** * 获取当前登录用户信息 * @return Json */ public function userInfo(): Json { $authHeader = $this->request->header('Authorization', ''); if (!preg_match('/Bearer\s+(.+)/i', $authHeader, $matches)) { return json([ 'code' => 401, 'msg' => '未登录' ]); } $tokenData = $this->verifyToken($matches[1]); if (!$tokenData || !isset($tokenData['user'])) { return json([ 'code' => 401, 'msg' => 'Token无效' ]); } $user = (array)$tokenData['user']; $user_id = $user['id']; $userData = AdminUser::where('id', $user_id) ->where('delete_time', null) ->field('id, account, name, phone, qq, sex, group_id, status, create_time, update_time') ->find(); if (!$userData) { return json([ 'code' => 404, 'msg' => '用户不存在' ]); } return json([ 'code' => 200, 'msg' => '获取成功', 'data' => $userData->toArray() ]); } public function getAdminUserFromToken(): array { return JwtService::getUserFromHeader($this->request->header('Authorization', '')); } public function loginInfo() { $loginInfo = SystemSiteSettings::select(); return json([ 'code' => 200, 'msg' => '获取成功', 'data' => $loginInfo ]); } /** * 获取极验3.0的id和key * @return Json */ public function getGeetest3Infos() { // 定义你需要的 label 列表 $targetLabels = [ 'geetest3ID', 'geetest3KEY' ]; $legalInfos = SystemSiteSettings::where('delete_time', null) ->whereIn('label', $targetLabels) // 仅筛选指定的 label ->field('label, value') ->select(); $this->logSuccess('站点设置管理', '查看极验3.0的id和key', [], $this->getAdminUserInfo()); return json([ 'code' => 200, 'msg' => '获取成功', 'data' => $legalInfos->toArray() ]); } /** * 获取极验4.0的id和key * @return Json */ public function getGeetest4Infos() { // 定义你需要的 label 列表 $targetLabels = [ 'geetest4ID', 'geetest4KEY' ]; $legalInfos = SystemSiteSettings::where('delete_time', null) ->whereIn('label', $targetLabels) // 仅筛选指定的 label ->field('label, value') ->select() ->toArray(); // 转换为前端需要的格式 $data = []; foreach ($legalInfos as $item) { if ($item['label'] === 'geetest4ID') { $data['captcha_id'] = $item['value']; } if ($item['label'] === 'geetest4KEY') { $data['captcha_key'] = $item['value']; } } $this->logSuccess('站点设置管理', '查看极验4.0的id和key', [], $this->getAdminUserInfo()); return json([ 'code' => 200, 'msg' => '获取成功', 'data' => $data ]); } /** * 判断是否开启验证 * @return Json */ public function getOpenVerify() { // 定义你需要的 label 列表 $targetLabels = [ 'openVerify', 'verifyModel' ]; $legalInfos = SystemSiteSettings::where('delete_time', null) ->whereIn('label', $targetLabels) // 仅筛选指定的 label ->field('label, value') ->select(); return json([ 'code' => 200, 'msg' => '获取成功', 'data' => $legalInfos->toArray() ]); } }