登录注册功能

This commit is contained in:
2025-05-05 09:44:50 +08:00
parent db54446f8b
commit 147b2d3fd5
29 changed files with 552 additions and 60 deletions

View File

@@ -2,7 +2,7 @@
namespace App\BaseApp;
use App\Service\UtilsService;
use App\Service\common\UtilsService;
use Exception;
use Illuminate\Http\JsonResponse;
use Psr\Container\ContainerExceptionInterface;

View File

@@ -3,7 +3,7 @@
namespace App\BaseApp;
use App\Models\UserModel;
use App\Service\UtilsService;
use App\Service\common\UtilsService;
class BaseService
{

View File

@@ -0,0 +1,37 @@
<?php
namespace App\Http\Controllers;
use App\BaseApp\BaseController;
use App\Service\LoginService;
class LoginController extends BaseController
{
//
public function __construct()
{
parent::__construct();
$this->service = LoginService::getInstance();
}
/**
* 登录
* @Method POST
* @return \Illuminate\Http\JsonResponse
* @throws \Exception
*/
public function login()
{
$this->insertField = [
'account', 'password', 'is_remember'
];
$param = $this->checkRequiredFields(request()->post());
return jok(
$this->service->login($param['account'], $param['password']),
'登录成功'
);
}
}

View File

@@ -0,0 +1,10 @@
<?php
namespace App\Http\Controllers;
use App\BaseApp\BaseController;
class UserController extends BaseController
{
//
}

View File

@@ -2,13 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* 分类表
*/
class CategoryModal extends Model
class CategoryModel extends BaseModel
{
//
protected $table = 'categories';
@@ -21,6 +21,6 @@ class CategoryModal extends Model
*/
public function projects(): HasMany
{
return $this->hasMany(ProjectModal::class, 'category_id', 'id');
return $this->hasMany(ProjectModel::class, 'category_id', 'id');
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 核心功能表
*/
class FeatureModal extends Model
class FeatureModel extends BaseModel
{
//
protected $table = 'features';

View File

@@ -2,13 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
/**
* 框架表
*/
class FrameworkModal extends Model
class FrameworkModel extends BaseModel
{
//
protected $table = 'frameworks';
@@ -21,6 +21,6 @@ class FrameworkModal extends Model
*/
public function projects()
{
return $this->belongsToMany(ProjectModal::class, 'project_frameworks_relations', 'framework_id', 'project_id');
return $this->belongsToMany(ProjectModel::class, 'project_frameworks_relations', 'framework_id', 'project_id');
}
}

View File

@@ -2,14 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
/**
* 标签表
*/
class LabelModal extends Model
class LabelModel extends BaseModel
{
//
protected $table = 'labels';
@@ -22,6 +21,6 @@ class LabelModal extends Model
*/
public function projects(): BelongsToMany
{
return $this->belongsToMany(ProjectModal::class, 'project_labels_relations', 'label_id', 'project_id');
return $this->belongsToMany(ProjectModel::class, 'project_labels_relations', 'label_id', 'project_id');
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 订单详情表
*/
class OrderItemModal extends Model
class OrderItemModel extends BaseModel
{
//
protected $table = 'order_items';

View File

@@ -2,14 +2,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
/**
* 订单表
*/
class OrderModal extends Model
class OrderModel extends BaseModel
{
//
protected $table = 'orders';
@@ -22,7 +22,7 @@ class OrderModal extends Model
*/
public function user()
{
return $this->hasOne(UserModal::class, 'id', 'user_id');
return $this->hasOne(UserModel::class, 'id', 'user_id');
}
/**
@@ -31,6 +31,6 @@ class OrderModal extends Model
*/
public function items(): HasMany
{
return $this->hasMany(OrderItemModal::class, 'order_id', 'id');
return $this->hasMany(OrderItemModel::class, 'order_id', 'id');
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 合作伙伴表
*/
class PartnerModal extends Model
class PartnerModel extends BaseModel
{
//
protected $table = 'partners';

View File

@@ -2,13 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use App\BaseApp\BaseModel;
/**
* 项目框架关联表
*/
class ProjectFrameworksRelationModal extends Model
class ProjectFrameworksRelationModel extends BaseModel
{
//
protected $table = 'project_frameworks_relations';

View File

@@ -2,13 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasOne;
/**
* 项目标签关联表
*/
class ProjectLabelRelationModal extends Model
class ProjectLabelRelationModel extends BaseModel
{
//
protected $table = 'project_label_relations';
@@ -21,7 +21,7 @@ class ProjectLabelRelationModal extends Model
*/
public function project(): HasOne
{
return $this->hasOne(ProjectModal::class, 'id', 'project_id');
return $this->hasOne(ProjectModel::class, 'id', 'project_id');
}
/**
@@ -30,6 +30,6 @@ class ProjectLabelRelationModal extends Model
*/
public function label(): HasOne
{
return $this->hasOne(LabelModal::class, 'id', 'label_id');
return $this->hasOne(LabelModel::class, 'id', 'label_id');
}
}

View File

@@ -2,7 +2,7 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
@@ -10,7 +10,7 @@ use Illuminate\Database\Eloquent\Relations\HasOne;
/**
* 项目表
*/
class ProjectModal extends Model
class ProjectModel extends BaseModel
{
//
protected $table = 'projects';
@@ -23,7 +23,7 @@ class ProjectModal extends Model
*/
public function user(): HasOne
{
return $this->hasOne(UserModal::class, 'id', 'user_id');
return $this->hasOne(UserModel::class, 'id', 'user_id');
}
/**
@@ -32,7 +32,7 @@ class ProjectModal extends Model
*/
public function author(): HasOne
{
return $this->hasOne(UserModal::class, 'id', 'author_id');
return $this->hasOne(UserModel::class, 'id', 'author_id');
}
/**
@@ -41,7 +41,7 @@ class ProjectModal extends Model
*/
public function labels(): BelongsToMany
{
return $this->belongsToMany(LabelModal::class, 'project_label_relations', 'project_id', 'label_id');
return $this->belongsToMany(LabelModel::class, 'project_label_relations', 'project_id', 'label_id');
}
/**
@@ -50,7 +50,7 @@ class ProjectModal extends Model
*/
public function screenshots(): HasMany
{
return $this->hasMany(ScreenshotModal::class, 'project_id', 'id');
return $this->hasMany(ScreenshotModel::class, 'project_id', 'id');
}
/**
@@ -59,7 +59,7 @@ class ProjectModal extends Model
*/
public function frameworks(): BelongsToMany
{
return $this->belongsToMany(FrameworkModal::class, 'project_frameworks_relations', 'project_id', 'framework_id');
return $this->belongsToMany(FrameworkModel::class, 'project_frameworks_relations', 'project_id', 'framework_id');
}
/**
@@ -68,7 +68,7 @@ class ProjectModal extends Model
*/
public function technologyStacks(): BelongsToMany
{
return $this->belongsToMany(TechnologyStackModal::class, 'project_technology_stacks_relations', 'project_id', 'technology_stacks_id');
return $this->belongsToMany(TechnologyStackModel::class, 'project_technology_stacks_relations', 'project_id', 'technology_stacks_id');
}
/**
@@ -77,7 +77,7 @@ class ProjectModal extends Model
*/
public function features(): HasMany
{
return $this->hasMany(FeatureModal::class, 'project_id', 'id');
return $this->hasMany(FeatureModel::class, 'project_id', 'id');
}
/**
@@ -86,6 +86,6 @@ class ProjectModal extends Model
*/
public function category(): HasOne
{
return $this->hasOne(CategoryModal::class, 'id', 'category_id');
return $this->hasOne(CategoryModel::class, 'id', 'category_id');
}
}

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 项目技术栈关联表
*/
class ProjectTechnologyStacksRelationModal extends Model
class ProjectTechnologyStacksRelationModel extends BaseModel
{
//
protected $table = 'project_technology_stacks_relations';

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 角色表
*/
class RoleModal extends Model
class RoleModel extends BaseModel
{
//
protected $table = 'roles';

View File

@@ -2,12 +2,12 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
/**
* 截图表
*/
class ScreenshotModal extends Model
class ScreenshotModel extends BaseModel
{
//
protected $table = 'screenshots';

View File

@@ -2,13 +2,13 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
/**
* 技术栈表
*/
class TechnologyStackModal extends Model
class TechnologyStackModel extends BaseModel
{
//
protected $table = 'technology_stacks';
@@ -21,6 +21,6 @@ class TechnologyStackModal extends Model
*/
public function projects(): BelongsToMany
{
return $this->belongsToMany(ProjectModal::class, 'project_technology_stack_relations', 'technology_stack_id', 'project_id');
return $this->belongsToMany(ProjectModel::class, 'project_technology_stack_relations', 'technology_stack_id', 'project_id');
}
}

View File

@@ -2,14 +2,14 @@
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use App\BaseApp\BaseModel;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
/**
* 用户表
*/
class UserModal extends Model
class UserModel extends BaseModel
{
//
protected $table = 'users';
@@ -22,7 +22,7 @@ class UserModal extends Model
*/
public function projects(): HasMany
{
return $this->hasMany(ProjectModal::class, 'user_id', 'id');
return $this->hasMany(ProjectModel::class, 'user_id', 'id');
}
/**
@@ -31,7 +31,7 @@ class UserModal extends Model
*/
public function projectsAuthor(): HasMany
{
return $this->hasMany(ProjectModal::class, 'author_id', 'id');
return $this->hasMany(ProjectModel::class, 'author_id', 'id');
}
/**
@@ -40,6 +40,6 @@ class UserModal extends Model
*/
public function roles(): HasOne
{
return $this->hasOne(RoleModal::class, 'id', 'role_id');
return $this->hasOne(RoleModel::class, 'id', 'role_id');
}
}

View 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;
}
}

View 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
View 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);
}
}

View 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);
}
}

View File

@@ -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;