tapi/app/service/admin/LoginService.php
2025-08-22 10:11:22 +08:00

120 lines
4.2 KiB
PHP

<?php
namespace app\service\admin;
use app\http\HttpAuth;
use Firebase\JWT\JWT;
use Firebase\JWT\Key;
use Hashids\Hashids;
use stdClass;
use app\entity\{SysLoginRecord, SysUser};
use UnexpectedValueException;
use app\enum\{UserLoginEnum, UserStatusEnum, UserTypeEnum};
use app\http\HttpClient;
use app\Request;
use app\validate\auth\LoginValidate;
use Exception;
use think\db\exception\{DataNotFoundException, DbException, ModelNotFoundException};
use think\exception\ValidateException;
class LoginService
{
/**
* 账号登录
* @param Request $request
* @param HttpClient $client
* @param string $username
* @param string $password
* @param string $code
* @param string $remember
* @return array
* @throws DataNotFoundException
* @throws DbException
* @throws ModelNotFoundException
*/
public function login(Request $request, HttpClient $client, string $username, string $password, string $code, string $remember): array
{
$clientName = $client->name;
validate(LoginValidate::class)
->scene($clientName . 'Login')
->check(compact('username', 'password', 'remember', 'code'));
$user = SysUser::where(['username' => $username])->find();
if (empty($user)) {
$this->saveLoginRecord($request, $username, UserLoginEnum::USERNAME_ERROR, "用户名错误");
throw new ValidateException("用户名或密码错误");
}
if (!password_verify($password, $user->password)) {
$this->saveLoginRecord($request, $username, UserLoginEnum::PASSWORD_ERROR, "密码错误");
throw new ValidateException("用户名或密码错误");
}
if ($user->status == UserStatusEnum::Disable->value) {
$this->saveLoginRecord($request, $username, UserLoginEnum::STATUS_DISABLED, "账号被禁用");
throw new ValidateException("账户不可用");
}
try {
$access_token = $user->getAccessToken();
$user = $user->append(['authorities', 'roles'])->toArray();
$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,
]);
}
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);
}
}