Files
nl-admin-api/app/Service/LoginService.php
2026-08-10 18:32:06 +08:00

186 lines
6.4 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\Service;
use App\BaseApp\BaseNotAuthService;
use App\Models\AdminModel;
use App\Models\LoginLogModel;
use App\Service\common\JWTService;
use App\Service\common\UserAgentService;
use App\Service\common\UtilsService;
use Exception;
use Illuminate\Support\Str;
/**
* 登录 / 注册服务:成功与失败均写登录日志,成功时更新 last_login_time
*/
class LoginService extends BaseNotAuthService
{
/**
* 账号密码登录
* 失败时先写日志再抛错,保证审计完整;成功始终更新 last_login_time
*
* @param string $phone 手机号/账号
* @param string $password 明文密码
* @return array 用户信息 + token
* @throws Exception
*/
public function login($phone, $password): array
{
$ua = UserAgentService::getInstance();
$equipment = $ua->parseEquipment();
$browser = $ua->parseBrowser();
$userModel = AdminModel::with(['role:id,name,value'])->where('phone', $phone)->first();
if (empty($userModel)) {
$this->writeLoginLog(0, (string) $phone, '', 1, '用户或密码错误', $equipment, $browser);
UtilsService::getInstance()->errorThrow('用户或密码错误!');
}
if (!password_verify($password, $userModel->password)) {
$this->writeLoginLog(
(int) $userModel->id,
(string) $phone,
(string) $userModel->nick_name,
1,
'用户或密码错误',
$equipment,
$browser
);
UtilsService::getInstance()->errorThrow('用户或密码错误!');
}
$updateData = [
'last_login_time' => get_time(),
'updated_at' => get_time(),
];
if ($userModel->ip !== get_ip()) {
$ipTable = json_decode($userModel->ip_table, true);
if (!in_array(get_ip(), $ipTable ?? [])) {
$ipTable[] = get_ip();
}
$updateData['ip'] = get_ip();
$updateData['ip_table'] = json_encode($ipTable);
}
$update = AdminModel::where('id', $userModel->id)->update($updateData);
if (!$update) {
$this->writeLoginLog(
(int) $userModel->id,
(string) $phone,
(string) $userModel->nick_name,
1,
'更新登录信息失败',
$equipment,
$browser
);
UtilsService::getInstance()->errorThrow('更新失败!');
}
$userModel = AdminModel::with(['role:id,name,value'])->where('id', $userModel->id)->first();
$this->writeLoginLog(
(int) $userModel->id,
(string) $userModel->phone,
(string) $userModel->nick_name,
0,
'登录成功',
$equipment,
$browser
);
$result = [
'id' => $userModel->id,
'phone' => $userModel->phone,
'nick_name' => $userModel->nick_name,
'avatar' => $userModel->avatar,
'email' => $userModel->email,
'role_id' => $userModel->role_id,
'role_name' => $userModel->role->name,
'role_value' => $userModel->role->value,
'ip' => $userModel->ip,
'ip_table' => $userModel->ip_table,
];
$token = JWTService::getInstance()->generateToken($result);
$result['token'] = $token;
return $result;
}
/**
* 注册管理员账号
*
* @param string $phone 手机号
* @param string $password 密码
* @param string $email 邮箱
* @param mixed $code 验证码(预留)
* @return array
* @throws Exception
*/
public function register($phone, $password, $email, $code): array
{
$userModel = AdminModel::where('phone', $phone)->first();
if ($userModel) {
UtilsService::getInstance()->errorThrow('账号已被占用!');
}
$createModel = AdminModel::create([
'phone' => $phone,
'email' => $email,
'password' => password_hash($password, PASSWORD_DEFAULT),
'nick_name' => '新用户' . Str::random(),
'avatar' => 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
'role_id' => 2,
'ip' => get_ip(),
'ip_table' => json_encode([get_ip()]),
'created_at' => get_time(),
]);
if (!$createModel) {
UtilsService::getInstance()->errorThrow('注册失败!');
}
$userInfo = AdminModel::with(['role:id,name,value'])->where('id', $createModel->id)->first();
$result = [
'id' => $userInfo->id,
'phone' => $userInfo->phone,
'nick_name' => $userInfo->nick_name,
'avatar' => $userInfo->avatar,
'email' => $userInfo->email ?? '',
'role_name' => $userInfo->role->name,
'role_value' => $userInfo->role->value,
'ip' => $userInfo->ip,
'ip_table' => $userInfo->ip_table,
];
$token = JWTService::getInstance()->generateToken($result);
$result['token'] = $token;
return $result;
}
/**
* 写入登录日志(失败也尽量落库,内部吞异常避免掩盖业务错误)
*
* @param int $userId 管理员 ID失败未知用户可为 0
* @param string $phone 登录账号
* @param string $nickName 昵称快照
* @param int $status 0成功 1失败
* @param string $message 结果说明
* @param string $equipment 操作系统
* @param string $browser 浏览器
*/
private function writeLoginLog(
int $userId,
string $phone,
string $nickName,
int $status,
string $message,
string $equipment,
string $browser
): void {
try {
LoginLogModel::insert([
'user_id' => $userId,
'phone' => $phone,
'nick_name' => $nickName,
'ip' => (string) get_ip(),
'equipment' => $equipment,
'browser' => $browser,
'status' => $status,
'message' => $message,
'created_at' => time(),
]);
} catch (\Throwable $e) {
// 日志失败不影响登录主流程
}
}
}