Files
x-server-mobile/backend/app/controller/AuthController.php
T
root fd364be4b6 fix: 扫码登录成功后返回简单页面,不重定向
移动端扫码完成后显示登录成功页面,用户可直接关闭,
不再重定向到前端页面。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-26 11:04:31 +08:00

314 lines
9.0 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
namespace app\controller;
use app\service\FeishuService;
use app\util\JwtUtil;
use app\model\User;
use app\model\Company;
use Webman\Http\Request;
use Webman\Http\Response;
class AuthController extends BaseController
{
/**
* 用户登录
*/
public function login(Request $request): Response
{
$username = $request->post('username');
$password = $request->post('password');
// TODO: 实现真实的登录逻辑
if (!$username || !$password) {
return $this->error('用户名或密码不能为空');
}
// 模拟用户数据(用于测试)
$user = User::first();
if (!$user) {
return $this->error('用户不存在');
}
$token = JwtUtil::encode([
'user_id' => $user->id,
'company_id' => $user->company_id,
'username' => $user->name,
]);
return $this->success([
'token' => $token,
'user' => $user,
]);
}
/**
* 飞书免登
*/
public function feishuLogin(Request $request): Response
{
$authCode = $request->post('auth_code');
$tenantKey = $request->post('tenant_key');
if (!$authCode) {
return $this->error('缺少授权码');
}
try {
$feishuService = new FeishuService();
// 根据 tenant_key 获取公司
$company = $feishuService->getCompanyByTenantKey($tenantKey);
if (!$company) {
return $this->error('公司不存在');
}
// 设置公司并获取用户信息
$feishuService->setCompany($company->id);
$feishuData = $feishuService->getUserInfo($authCode);
// 创建或更新用户
$user = $feishuService->createOrUpdateUser($feishuData, $company->id);
// 生成 JWT Token
$token = JwtUtil::encode([
'user_id' => $user->id,
'company_id' => $user->company_id,
'feishu_user_id' => $user->feishu_user_id,
'union_id' => $user->union_id,
]);
return $this->success([
'token' => $token,
'user' => $user->load('company'),
]);
} catch (\Exception $e) {
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');
if (!$tenantKey) {
return $this->error('缺少租户密钥');
}
try {
$feishuService = new \app\service\FeishuService();
// 根据 tenant_key 获取公司
$company = $feishuService->getCompanyByTenantKey($tenantKey);
if (!$company) {
return $this->error('公司不存在');
}
$feishuService->setCompany($company->id);
// 生成登录会话
$loginSession = \app\model\FeishuLoginSession::create([
'company_id' => $company->id,
'tenant_key' => $tenantKey,
'status' => 'pending',
'expires_at' => date('Y-m-d H:i:s', time() + 300), // 5分钟过期
]);
// 构建扫码登录 URL(使用官方 passport 端点)
$appId = 'cli_a8033d607cba500d';
// 使用固定的 redirect_uri,session_id 通过 state 传递
$redirectUri = urlencode("https://xsm.dev.hnxinyouhe.com/login/callback");
$authUrl = "https://passport.feishu.cn/suite/passport/oauth/authorize?client_id={$appId}&redirect_uri={$redirectUri}&response_type=code&state={$loginSession->id}";
// 生成二维码内容(返回 URL,前端生成二维码)
return $this->success([
'session_id' => $loginSession->id,
'auth_url' => $authUrl,
'expires_at' => $loginSession->expires_at,
]);
} catch (\Exception $e) {
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->feishu_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');
if (!$sessionId) {
return $this->error('缺少会话ID');
}
if (!$authCode) {
return $this->error('缺少授权码');
}
try {
$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('二维码已过期');
}
// 使用 session 的公司信息
$feishuService = new \app\service\FeishuService();
$feishuService->setCompany($session->company_id);
// 获取用户信息
$feishuData = $feishuService->getUserInfo($authCode);
// 创建或更新用户
$user = $feishuService->createOrUpdateUser($feishuData, $session->company_id);
// 更新会话状态
$session->status = 'success';
$session->user_id = $user->id;
$session->save();
// 返回简单页面,让用户知道可以关闭了
return new \Webman\Http\Response(200, [], '<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>登录成功</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
margin: 0;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: #fff;
text-align: center;
}
.container {
padding: 40px 20px;
}
h1 {
margin: 0 0 10px 0;
font-size: 28px;
}
p {
margin: 10px 0 0 0;
font-size: 16px;
opacity: 0.9;
}
.icon {
font-size: 64px;
margin-bottom: 20px;
}
</style>
</head>
<body>
<div class="container">
<div class="icon">✅</div>
<h1>登录成功</h1>
<p>您可以关闭此页面返回电脑端继续操作</p>
</div>
</body>
</html>');
} catch (\Exception $e) {
return $this->error($e->getMessage());
}
}
}