125 lines
4.4 KiB
PHP
125 lines
4.4 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,
|
|
'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);
|
|
}
|
|
} |