name; validate(LoginValidate::class) ->scene($clientName . 'Login') ->check(compact('username', 'password', 'remember', 'code')); $userModel = SysUser::where(['username' => $username])->find(); if (empty($userModel)) { $this->saveLoginRecord($request, $username, UserLoginEnum::USERNAME_ERROR, "用户名错误"); throw new ValidateException("用户名或密码错误"); } if (!password_verify($password, $userModel->password)) { $this->saveLoginRecord($request, $username, UserLoginEnum::PASSWORD_ERROR, "密码错误"); throw new ValidateException("用户名或密码错误"); } if ($userModel->status == UserStatusEnum::Disable->value) { $this->saveLoginRecord($request, $username, UserLoginEnum::STATUS_DISABLED, "账号被禁用"); throw new ValidateException("账户不可用"); } try { $access_token = $userModel->getAccessToken(); $user = $userModel->append(['authorities', 'roles'])->toArray(); // 保存客户端信息 $this->saveClientRecord($client, $userModel); // 保存登录日志 $this->saveLoginRecord($request, $username, UserLoginEnum::LOGIN_SUCCESS, "登录成功"); } catch (Exception $e) { $this->saveLoginRecord($request, $username, UserLoginEnum::LOGIN_EXCEPTION, $e->getMessage()); throw $e; } return compact('user', 'access_token'); } /** * 保存登录记录 * @param Request $request * @param string $username * @param UserLoginEnum $loginType * @param string $comments * @return void */ private function saveLoginRecord(Request $request, string $username, UserLoginEnum $loginType, string $comments): void { $sysLoginRecord = new SysLoginRecord(); $sysLoginRecord->save([ 'username' => $username, 'os' => $request->getOs(), 'device' => $request->getDevice(), 'browser' => $request->getBrowser(), 'ip' => $request->ip(), 'comments' => $comments, 'login_type' => $loginType->value, 'context_id' => $request->contextId, ]); } public function logout(Request $request, SysUser $user) { $this->saveLoginRecord($request, $user->username,UserLoginEnum::LOGIN_EXIT, '退出登录'); } public function checkUserAccessToken(string $token): HttpAuth { if (empty($token)) { throw new ValidateException('凭证错误'); } try { $jwtKey = (string)config('admin.jwt_key', ''); $headers = new stdClass(); $data = JWT::decode($token, new Key($jwtKey, 'HS256'), $headers); } catch (UnexpectedValueException $e) { if ($e->getMessage() == "Expired token") { throw new ValidateException('凭证过期'); } throw new ValidateException('校验失败' . $e->getMessage()); } if ($data->exp <= (time() - 180)) { // 还要三分钟就要过期 throw new ValidateException('凭证过期'); } $hashids = new Hashids($jwtKey, 8); $user_id = $hashids->decode($data->uid)[0] ?? 0; if (empty($user_id)) { throw new ValidateException('凭证错误'); } return new HttpAuth($user_id, UserTypeEnum::USER); } public function getVisitor(\think\Request $request): HttpAuth { return new HttpAuth(-1, UserTypeEnum::VISITOR); } private function saveClientRecord(HttpClient $client, SysUser|\app\model\SysUser $userModel) { $clientModel = SysUserClient::where([ 'client_id'=> $client->id, 'client_name'=> $client->name, 'user_id' => $userModel->user_id ])->findOrEmpty(); $clientUpdate = []; if($clientModel->isEmpty()) { $clientUpdate['client_id'] = $client->id; $clientUpdate['user_id'] = $userModel->user_id; $clientUpdate['client_name'] = $client->name; $clientUpdate['create_time'] = date('Y-m-d H:i:s'); } $clientUpdate['client_version'] = $client->version; $clientUpdate['last_online_time'] = date('Y-m-d H:i:s'); $clientModel->save($clientUpdate); } }