登录注册功能
This commit is contained in:
107
app/Service/LoginService.php
Normal file
107
app/Service/LoginService.php
Normal file
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Models\UserModel;
|
||||
use App\Service\common\JWTService;
|
||||
use App\Service\common\UtilsService;
|
||||
use Illuminate\Support\Str;
|
||||
|
||||
class LoginService
|
||||
{
|
||||
|
||||
/**
|
||||
* @var mixed 单例实例,确保该类只有一个全局实例
|
||||
*/
|
||||
private static mixed $_instance;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
public function login($account, $password)
|
||||
{
|
||||
$userModel = UserModel::where('account', $account)->first();
|
||||
if (empty($userModel)) {
|
||||
return $this->register($account, $password);
|
||||
}
|
||||
|
||||
if (!password_verify($password, $userModel->password)) {
|
||||
UtilsService::getInstance()->errorThrow('用户或密码错误!');
|
||||
}
|
||||
|
||||
if ($userModel->ip !== get_ip()) {
|
||||
$ipTable = json_decode($userModel->ip_table, true);
|
||||
if (!in_array(get_ip(), $ipTable)) {
|
||||
$ipTable[] = get_ip();
|
||||
}
|
||||
$update = UserModel::where('id', $userModel->id)->update([
|
||||
'ip' => get_ip(),
|
||||
'ip_table' => json_encode($ipTable),
|
||||
'updated_at' => get_time()
|
||||
]);
|
||||
|
||||
if (!$update) {
|
||||
UtilsService::getInstance()->errorThrow('更新失败!');
|
||||
}
|
||||
|
||||
$userModel = UserModel::where('id', $userModel->id)->first();
|
||||
}
|
||||
$result = [
|
||||
'id' => $userModel->id,
|
||||
'account' => $userModel->account,
|
||||
'nick_name' => $userModel->nick_name,
|
||||
'avatar' => $userModel->avatar,
|
||||
'ip' => $userModel->ip,
|
||||
'ip_table' => $userModel->ip_table,
|
||||
];
|
||||
$token = JWTService::getInstance()->generateToken($result);
|
||||
$result['token'] = $token;
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function register($account, $password)
|
||||
{
|
||||
$userModel = UserModel::where('account', $account)->first();
|
||||
if ($userModel) {
|
||||
UtilsService::getInstance()->errorThrow('账号已被占用!');
|
||||
}
|
||||
|
||||
$createModel = UserModel::create([
|
||||
'account' => $account,
|
||||
'password' => password_hash($password, PASSWORD_DEFAULT),
|
||||
'nick_name' => '新用户'. Str::random(),
|
||||
'avatar' => 'https://pic.rmb.bdstatic.com/bjh/80852bfe7c321988191838517ba64e309354.jpeg@h_1280',
|
||||
'ip' => get_ip(),
|
||||
'ip_table' => json_encode([get_ip()]),
|
||||
'created_at' => get_time()
|
||||
]);
|
||||
|
||||
if (!$createModel) {
|
||||
UtilsService::getInstance()->errorThrow('注册失败!');
|
||||
}
|
||||
|
||||
$result = [
|
||||
'id' => $createModel->id,
|
||||
'account' => $createModel->account,
|
||||
'nick_name' => $createModel->nick_name,
|
||||
'avatar' => $createModel->avatar,
|
||||
'ip' => $createModel->ip,
|
||||
'ip_table' => $createModel->ip_table,
|
||||
];
|
||||
$token = JWTService::getInstance()->generateToken($result);
|
||||
$result['token'] = $token;
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
10
app/Service/UserService.php
Normal file
10
app/Service/UserService.php
Normal file
@@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\BaseApp\BaseService;
|
||||
|
||||
class UserService extends BaseService
|
||||
{
|
||||
|
||||
}
|
||||
112
app/Service/common/JWTService.php
Executable file
112
app/Service/common/JWTService.php
Executable file
@@ -0,0 +1,112 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use Exception;
|
||||
|
||||
class JWTService
|
||||
{
|
||||
private static mixed $_instance;
|
||||
private string $secretKey = 'cc_spa_jwt_secret_key'; // 请替换为你的密钥
|
||||
|
||||
private string $token;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 Token
|
||||
* @return $this|null
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getToken(): null|static
|
||||
{
|
||||
$token = request()->bearerToken();
|
||||
if (empty($token)) return UtilsService::getInstance()->notAuth('请先登录');
|
||||
$this->token = $token;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成 JWT Token
|
||||
* @param array $data 要嵌入到 token 中的数据
|
||||
* @return string
|
||||
*/
|
||||
public function generateToken(array $data): string
|
||||
{
|
||||
$issuedAt = time();
|
||||
$expirationTime = $issuedAt + config('xk.redis.jwt_ttl');
|
||||
|
||||
$payload = [
|
||||
'iat' => $issuedAt,
|
||||
'exp' => $expirationTime,
|
||||
'data' => $data
|
||||
];
|
||||
|
||||
return JWT::encode($payload, $this->secretKey, 'HS256');
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析 JWT Token
|
||||
* @return object|null 返回解码后的 payload 或者 null 如果验证失败
|
||||
* @throws Exception
|
||||
*/
|
||||
public function parseToken(): ?object
|
||||
{
|
||||
try {
|
||||
if (empty($this->token)) return UtilsService::getInstance()->notAuth('请先登录');
|
||||
return JWT::decode($this->token, new Key($this->secretKey, 'HS256'));
|
||||
} catch (Exception $e) {
|
||||
return UtilsService::getInstance()->notAuth('【1】Token解析失败!请重新登录:'. $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 解析 JWT Token
|
||||
* @return array|null 返回解码后的 payload 或者 null 如果验证失败
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getUserInfo(): ?array
|
||||
{
|
||||
try {
|
||||
$jwt = $this->parseToken();
|
||||
$user = RedisService::getInstance()->init(config('xk.redis.jwt'))->get($jwt->data->id);
|
||||
if (empty($user)) return UtilsService::getInstance()->notAuth('登录状态过期');
|
||||
return json_decode($user, true);
|
||||
} catch (Exception $e) {
|
||||
return UtilsService::getInstance()->notAuth('【2】Token解析失败!请重新登录:'. $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 续签 JWT Token
|
||||
* @return string|null 新的 JWT 字符串或者 null 如果原 token 已过期或无效
|
||||
* @throws Exception
|
||||
*/
|
||||
public function refreshToken(): ?string
|
||||
{
|
||||
$decoded = $this->parseToken();
|
||||
if ($decoded === null || !property_exists($decoded, 'data')) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->generateToken((array)$decoded->data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
94
app/Service/common/RedisService.php
Executable file
94
app/Service/common/RedisService.php
Executable file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service\common;
|
||||
|
||||
use Illuminate\Support\Facades\Redis;
|
||||
|
||||
class RedisService
|
||||
{
|
||||
|
||||
private static mixed $_instance;
|
||||
|
||||
private $prefix = 'default';
|
||||
|
||||
private $redis;
|
||||
|
||||
/**
|
||||
* 获取实例
|
||||
* @return null|static
|
||||
*/
|
||||
public static function getInstance(): null|static
|
||||
{
|
||||
$name = get_called_class();
|
||||
if (!isset(self::$_instance[$name])) {
|
||||
self::$_instance[$name] = new static();
|
||||
}
|
||||
|
||||
return self::$_instance[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化
|
||||
* @param string $prefix
|
||||
* @return RedisService
|
||||
*/
|
||||
public function init(string $prefix = 'default'): static
|
||||
{
|
||||
$this->redis = Redis::class;
|
||||
$this->prefix = $prefix;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置缓存
|
||||
* @param $key
|
||||
* @param $value
|
||||
* @param int $expire
|
||||
* @return true
|
||||
*/
|
||||
public function set($key, $value, int $expire = 0): true
|
||||
{
|
||||
$this->redis::set($this->prefix . $key, $value);
|
||||
if ($expire > 0) {
|
||||
$this->redis::expire($this->prefix . $key, $expire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 累加
|
||||
* @param $key
|
||||
* @param int $value
|
||||
* @param int $expire
|
||||
* @return true
|
||||
*/
|
||||
public function incr($key, int $value = 1, int $expire = 0): true
|
||||
{
|
||||
$this->redis::incr($this->prefix . $key, $value);
|
||||
if ($expire > 0) {
|
||||
$this->redis::expire($this->prefix . $key, $expire);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取缓存
|
||||
*
|
||||
* @param $key
|
||||
* @return mixed
|
||||
*/
|
||||
public function get($key): mixed
|
||||
{
|
||||
return $this->redis::get($this->prefix . $key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 删除缓存
|
||||
* @param $key
|
||||
* @return bool
|
||||
*/
|
||||
public function del($key): bool
|
||||
{
|
||||
return $this->redis::del($this->prefix . $key);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace App\Service;
|
||||
namespace App\Service\common;
|
||||
|
||||
use App\Enum\ErrorEnum;
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Illuminate\Routing\Route;
|
||||
use Illuminate\Support\Facades\Route;
|
||||
use Random\RandomException;
|
||||
use ReflectionClass;
|
||||
|
||||
Reference in New Issue
Block a user