post('username'); $password = $request->post('password'); if (!$username || !$password) { return $this->error('用户名或密码不能为空'); } // 通过邮箱或手机号查找用户 $user = User::where(function ($query) use ($username) { $query->where('email', $username) ->orWhere('phone', $username); })->where('status', 1) ->first(); if (!$user) { return $this->error('用户不存在或已被禁用'); } // 验证密码(如果没有设置密码,提示使用飞书登录) if (!$user->password) { return $this->error('该账号未设置密码,请使用飞书登录'); } if (!password_verify($password, $user->password)) { return $this->error('密码错误'); } // 生成 token $token = JwtUtil::encode([ 'user_id' => $user->id, 'company_id' => $user->company_id, 'username' => $user->name, ]); return $this->success([ 'token' => $token, 'user' => $user->load('company'), ]); } /** * 飞书免登 */ public function feishuLogin(Request $request): Response { $authCode = $request->post('auth_code'); $appId = $request->post('app_id'); $tenantKey = $request->post('tenant_key'); if (!$authCode) { return $this->error('缺少授权码'); } try { $feishuService = new FeishuService(); // 方式1: 根据 app_id 查找飞书应用配置(推荐) if ($appId) { error_log("🔍 使用 app_id 查找配置: {$appId}"); // 根据 app_id 查找飞书应用 $feishuApp = \app\model\CompanyFeishuApp::where('app_id', $appId) ->where('status', 1) ->first(); if (!$feishuApp) { return $this->error('飞书应用配置不存在'); } $companyId = $feishuApp->company_id; error_log("✅ 找到飞书应用配置: company_id={$companyId}, feishu_app_id={$feishuApp->id}"); $feishuService->setCompany($companyId); } // 方式2: 根据 tenant_key 查找(兼容旧版) elseif ($tenantKey) { error_log("🔍 使用 tenant_key 查找配置: {$tenantKey}"); $company = $feishuService->getCompanyByTenantKey($tenantKey); if (!$company) { return $this->error('公司不存在'); } $companyId = $company->id; // 获取默认飞书应用 $feishuApp = \app\model\CompanyFeishuApp::where('company_id', $companyId) ->where('system_id', 1) ->where('status', 1) ->first(); if (!$feishuApp) { return $this->error('未配置飞书应用'); } error_log("✅ 找到公司配置: company_id={$companyId}, feishu_app_id={$feishuApp->id}"); $feishuService->setCompany($companyId); // 设置应用ID $appId = $feishuApp->id; } else { return $this->error('缺少 app_id 或 tenant_key 参数'); } // 获取用户信息 $feishuData = $feishuService->getUserInfo($authCode); error_log("👤 获取到用户信息: " . json_encode($feishuData)); // 创建或更新用户(传递应用ID) $user = $feishuService->createOrUpdateUser($feishuData, $companyId, $appId); // 生成 JWT Token $token = JwtUtil::encode([ 'user_id' => $user->id, 'company_id' => $user->company_id, 'feishu_app_id' => $user->feishu_app_id, 'union_id' => $user->union_id, ]); error_log("✅ 登录成功: user_id={$user->id}, company_id={$user->company_id}"); return $this->success([ 'token' => $token, 'user' => $user->load('company'), ]); } catch (\Exception $e) { error_log("❌ 登录失败: " . $e->getMessage()); return $this->error($e->getMessage()); } } /** * 获取当前用户信息 */ public function me(Request $request): Response { $userId = $this->getUserId($request); if (!$userId) { return $this->error('未登录', 401); } $user = User::with('company')->find($userId); if (!$user) { return $this->error('用户不存在'); } return $this->success($user); } /** * 生成飞书扫码登录二维码 */ public function qrcodeLogin(Request $request): Response { $tenantKey = $request->post('tenant_key'); $appId = $request->post('app_id'); error_log("📱 qrcodeLogin - tenant_key: {$tenantKey}, app_id: {$appId}"); try { $feishuService = new \app\service\FeishuService(); $companyId = null; $feishuApp = null; // 方式1: 根据 app_id 查找飞书应用配置(推荐) if ($appId) { $feishuApp = \app\model\CompanyFeishuApp::where('app_id', $appId) ->where('status', 1) ->first(); if (!$feishuApp) { return $this->error('飞书应用配置不存在'); } $companyId = $feishuApp->company_id; error_log("✅ 通过 app_id 找到配置: company_id={$companyId}"); } // 方式2: 根据 tenant_key 查找(兼容旧版) elseif ($tenantKey) { $company = $feishuService->getCompanyByTenantKey($tenantKey); if (!$company) { return $this->error('公司不存在'); } $companyId = $company->id; // 获取默认飞书应用 $feishuApp = \app\model\CompanyFeishuApp::where('company_id', $companyId) ->where('system_id', 1) ->where('status', 1) ->first(); if (!$feishuApp) { return $this->error('未配置飞书应用'); } error_log("✅ 通过 tenant_key 找到配置: company_id={$companyId}"); } else { return $this->error('缺少 app_id 或 tenant_key 参数'); } $feishuService->setCompany($companyId); // 生成登录会话 $loginSession = \app\model\FeishuLoginSession::create([ 'company_id' => $companyId, 'tenant_key' => $tenantKey, 'feishu_app_id' => $feishuApp->id, 'status' => 'pending', 'expires_at' => date('Y-m-d H:i:s', time() + 300), // 5分钟过期 ]); // 构建扫码登录 URL $redirectUri = urlencode("https://xsm.dev.hnxinyouhe.com/login/callback"); $authUrl = "https://passport.feishu.cn/suite/passport/oauth/authorize?client_id={$feishuApp->app_id}&redirect_uri={$redirectUri}&response_type=code&state={$loginSession->id}"; error_log("✅ 生成二维码会话: session_id={$loginSession->id}"); return $this->success([ 'session_id' => $loginSession->id, 'auth_url' => $authUrl, 'expires_at' => $loginSession->expires_at, ]); } catch (\Exception $e) { error_log("❌ qrcodeLogin 失败: " . $e->getMessage()); return $this->error($e->getMessage()); } } /** * 轮询扫码登录状态 */ public function qrcodeLoginStatus(Request $request): Response { $sessionId = $request->get('session_id'); if (!$sessionId) { return $this->error('缺少会话ID'); } $session = \app\model\FeishuLoginSession::find($sessionId); if (!$session) { return $this->error('登录会话不存在'); } // 检查是否过期 if (strtotime($session->expires_at) < time()) { $session->status = 'expired'; $session->save(); return $this->error('二维码已过期,请刷新重试'); } // 返回当前状态 if ($session->status === 'success') { // 生成 token $user = \app\model\User::find($session->user_id); if (!$user) { return $this->error('用户不存在'); } $token = \app\util\JwtUtil::encode([ 'user_id' => $user->id, 'company_id' => $user->company_id, 'feishu_user_id' => $user->feishu_user_id, 'union_id' => $user->union_id, ]); // 清除会话 $session->delete(); return $this->success([ 'status' => 'success', 'token' => $token, 'user' => $user->load('company'), ]); } else if ($session->status === 'expired') { return $this->error('二维码已过期,请刷新重试'); } else { // pending 或 scanning return $this->success([ 'status' => $session->status, ]); } } /** * 飞书扫码登录回调(飞书授权后的回调) */ public function qrcodeLoginCallback(Request $request): Response { // 从 state 参数获取 session_id $sessionId = $request->get('state'); // OAuth 2.0 标准参数是 code $authCode = $request->get('code'); error_log("🔔 QRCode callback received - session_id: {$sessionId}, code: " . substr($authCode ?? 'null', 0, 20) . "..."); // 如果没有参数,直接返回空页面(可能是 QR SDK 的预检请求) if (!$sessionId && !$authCode) { error_log("ℹ️ Callback called without parameters, returning empty page"); return new \Webman\Http\Response(200, ['Content-Type' => 'text/html; charset=utf-8'], ''); } if (!$sessionId) { error_log("❌ Callback missing session_id"); return $this->error('缺少会话ID'); } if (!$authCode) { error_log("❌ Callback missing auth_code"); return $this->error('缺少授权码'); } try { $session = \app\model\FeishuLoginSession::find($sessionId); error_log("🔍 Session found: " . ($session ? "id={$session->id}, status={$session->status}" : "null")); if (!$session) { error_log("❌ Session not found for id: {$sessionId}"); return $this->error('登录会话不存在'); } // 检查是否过期 if (strtotime($session->expires_at) < time()) { error_log("⏰ Session expired at: {$session->expires_at}"); $session->status = 'expired'; $session->save(); return $this->error('二维码已过期'); } error_log("🔄 Processing login for company_id: {$session->company_id}, feishu_app_id: {$session->feishu_app_id}"); // 使用 session 的公司信息 $feishuService = new \app\service\FeishuService(); $feishuService->setCompany($session->company_id); // 获取用户信息 $feishuData = $feishuService->getUserInfo($authCode); error_log("👤 Got user info: " . json_encode($feishuData)); // 创建或更新用户(传递飞书应用ID) $user = $feishuService->createOrUpdateUser($feishuData, $session->company_id, $session->feishu_app_id); error_log("✅ User created/updated: user_id={$user->id}"); // 更新会话状态 $session->status = 'success'; $session->user_id = $user->id; $saved = $session->save(); error_log("💾 Session save result: " . ($saved ? 'success' : 'failed') . ", new status: {$session->status}"); // 生成 JWT Token $token = \app\util\JwtUtil::encode([ 'user_id' => $user->id, 'company_id' => $user->company_id, 'feishu_user_id' => $user->feishu_user_id, 'union_id' => $user->union_id, ]); error_log("🎫 Generated token for user: {$user->id}"); // 返回成功页面(包含 token,前端会保存到 localStorage) $userName = htmlspecialchars($user->name ?? '用户'); // 准备用户数据JSON $userJson = json_encode([ 'id' => $user->id, 'name' => $user->name, 'email' => $user->email, 'avatar' => $user->avatar, 'phone' => $user->phone, 'company_id' => $user->company_id, 'status' => $user->status, ], JSON_HEX_APOS | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_UNESCAPED_UNICODE); $html = << 登录成功
✅

登录成功!

欢迎回来,{$userName}

正在跳转到应用...

HTML; return new \Webman\Http\Response(200, ['Content-Type' => 'text/html; charset=utf-8'], $html); } catch (\Exception $e) { return $this->error($e->getMessage()); } } }