validateUser($data['account'], $data['password']); // 验证系统编码,返回系统对象 $system = $this->validateSystem($data['system_code']); // 验证用户对该系统是否有访问权限 $this->validateSystemPermission($user, $system); // 准备 JWT 令牌的负载数据 $payload = $this->preparePayload($user, $system); // 根据负载数据生成访问令牌 $token = $this->generateAccessToken($payload); // 根据用户 ID 生成刷新令牌 $refreshToken = $this->generateRefreshToken($user->id); // 返回包含访问令牌、刷新令牌和令牌过期时间的数组 return [ 'access_token' => $token, 'refresh_token' => $refreshToken, 'expires_in' => config('jwt.jwt_expiration'), ]; } /** * 飞书登录 * * @param array $data * @return array */ public function feishuLogin(array $data): array { $feishuUserInfo = $this->getFeishuUserInfo($data['feishu_code']); $user = $this->getOrCreateUser($feishuUserInfo); $system = $this->validateSystem($data['system_code']); $this->validateSystemPermission($user, $system); $payload = $this->preparePayload($user, $system); $token = $this->generateAccessToken($payload); $refreshToken = $this->generateRefreshToken($user->id); return [ 'access_token' => $token, 'refresh_token' => $refreshToken, 'expires_in' => config('jwt.jwt_expiration'), ]; } /** * 扫码登录 * * @param array $data * @return array */ public function qrCodeLogin(array $data): array { $userId = $this->validateQrCodeToken($data['qr_code_token']); $user = User::find($userId); if (!$user || $user->status != 1) { throw new \Exception('用户无效', 403); } $system = $this->validateSystem($data['system_code']); $this->validateSystemPermission($user, $system); $payload = $this->preparePayload($user, $system); $token = $this->generateAccessToken($payload); $refreshToken = $this->generateRefreshToken($user->id); return [ 'access_token' => $token, 'refresh_token' => $refreshToken, 'expires_in' => config('jwt.jwt_expiration'), ]; } /** * 验证用户信息 * * @param string $account * @param string $password * @return User|null */ private function validateUser(string $account, string $password) { $user = User::byAccount($account)->first(); if (!$user || !password_verify($password, $user->password)) { throw new \Exception('账号或密码错误', 401); } if ($user->status != 1) { throw new \Exception('账号已禁用', 403); } return $user; } /** * 验证系统信息 * * @param string $systemCode * @return Systems|null */ private function validateSystem(string $systemCode) { $system = Systems::where('code', $systemCode)->first(); if (!$system) { throw new \Exception('系统不存在', 403); } return $system; } /** * 验证用户系统权限 * * @param User $user * @param Systems $system */ private function validateSystemPermission(User $user, Systems $system) { if ($system->is_role) { $systemIds = $user->systems->pluck('id')->toArray(); if (!in_array($system->id, $systemIds)) { throw new \Exception('无该系统权限', 403); } } } /** * 准备 JWT 负载 * * @param User $user * @param Systems $system * @return array */ private function preparePayload(User $user, Systems $system) { $payload = [ 'uid' => $user->id, 'sub' => 'user_'.$user->id, 'aud' => $system->domain_url, 'role_ids' => [], 'system_ids' => [] ]; if ($system->is_role) { $systemIds = $user->systems->pluck('id')->toArray(); $payload['role_ids'] = $user->roles->pluck('id')->toArray(); $payload['system_ids'] = $systemIds; } return $payload; } /** * 生成访问令牌 * * @param array $payload * @return string */ private function generateAccessToken(array $payload) { return (new Jwt())->generateToken($payload); } // private function verifyRefreshToken(string $token) // { // return (new Jwt())->verifyToken($token); // } /** * 生成刷新令牌 * * @param int $userId * @return string */ private function generateRefreshToken(int $userId) { $refreshToken = bin2hex(random_bytes(32)); Cache::set("refresh_token:{$refreshToken}", $userId, config('jwt.jwt_refresh_token_expiration')); return $refreshToken; } /** * 调用飞书 API 获取用户信息 * * @param string $code * @return array */ private function getFeishuUserInfo(string $code) { // 实际实现需要调用飞书 API,这里只是示例 return [ 'user_id' => 'feishu_user_123', 'name' => '飞书用户', ]; } /** * 根据飞书用户信息查找或创建本地用户 * * @param array $feishuUserInfo * @return User */ private function getOrCreateUser(array $feishuUserInfo) { // 实际实现需要根据飞书用户信息查找或创建本地用户,这里只是示例 $user = User::where('feishu_user_id', $feishuUserInfo['user_id'])->first(); if (!$user) { $user = new User(); $user->feishu_user_id = $feishuUserInfo['user_id']; $user->name = $feishuUserInfo['name']; $user->status = 1; $user->save(); } return $user; } /** * 验证扫码令牌 * * @param string $qrCodeToken * @return int */ private function validateQrCodeToken(string $qrCodeToken) { // 实际实现需要验证扫码令牌,这里只是示例 $userId = Cache::get("qr_code_token:{$qrCodeToken}"); if (!$userId) { throw new \Exception('扫码令牌无效或已过期', 401); } return $userId; } /** * 处理用户注册逻辑 * * @param array $data * @return User */ public function register(array $data) { $userSnModel = new UserSn(); $sn = $userSnModel->where('user_id', '=', 0)->inRandomOrder()->first(); if (!$sn) { throw new BusinessException('未找到适用编号'); } $data['sn'] = $sn->user_sn; $data['password'] = password_hash($data['password'], PASSWORD_DEFAULT); $user = User::create($data); return $this->updateUserId($user->id, $sn->user_sn); } public function updateUserId($userId, $userSn) { $userSn = User::where('user_sn', $userSn)->first(); if (!$userSn) { throw new BusinessException('用户编号不存在'); } return $userSn->update([ 'user_id' => $userId ]); } /** * 校验token */ public function verifyToken(string $token): array { $payload = (new Jwt())->verifyToken($token); if (Cache::has("token_blacklist:{$token}")) { throw new \Exception('token已失效', 403); } return (array)$payload; } /** * 刷新token * @param string $refreshToken * @return array */ public function refreshToken(string $refreshToken): array { $userId = Cache::get("refresh_token:{$refreshToken}"); if (!$userId) { throw new \Exception('refresh_token无效或已过期', 401); } $user = User::find($userId); if (!$user || $user->status != 1) { throw new \Exception('用户无效', 403); } // 获取角色ID、系统ID(和你登录时保持一致) $role_ids = $user->roles ? $user->roles->pluck('id')->toArray() : []; $system_ids = $user->systems ? $user->systems->pluck('id')->toArray() : []; $payload = [ 'uid' => $user->id, 'sub' => 'user_' . $user->id, 'role_ids' => $role_ids, 'system_ids' => $system_ids, ]; // 可补充aud、exp等字段,保持和登录生成payload一致 $token = (new Jwt())->generateToken($payload); return [ 'access_token' => $token, 'expires_in' => config('jwt.jwt_expiration'), ]; } /** * 登出,将token加入黑名单 */ public function logout(?string $token) { if ($token) { Cache::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration')); } } public function blockToken(string $token) { if (!$token) { throw new \Exception('token不能为空', 422); } // 加入黑名单 Cache::set("token_blacklist:{$token}", 1, config('jwt.jwt_expiration')); } }