mirror of
https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git
synced 2025-12-25 18:17:49 +08:00
Compare commits
13 Commits
8665b27294
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 5890122a37 | |||
| b405585bc7 | |||
| 5d2f32b22b | |||
| 082c15d697 | |||
| 21331655f9 | |||
| be0d0913b6 | |||
| c1d8f02491 | |||
| 2613b031ae | |||
| a6d6738ab2 | |||
| b1713d8476 | |||
| 5ed0e2d4f5 | |||
| 1eae4171f6 | |||
| 8046676669 |
21
.env.example
21
.env.example
@@ -1,22 +1,25 @@
|
||||
APP_NAME=sfyy
|
||||
APP_NAME=ctext
|
||||
APP_ENV=dev
|
||||
APP_DEBUG=false
|
||||
|
||||
APP_URL=http://127.0.0.1:9501
|
||||
|
||||
JWT_SECRET=azOVxsOWt3r0ozZNz8Ss429ht0T8z6OpeIJAIwNp6X0xqrbEY2epfIWyxtC1qSNM8eD6/LQ/SahcQi2ByXa/2A==
|
||||
JWT_ADMIN_SECRET=azOVxsOWt3r0ozZNz8Ss429ht0T8z6OpeIJAIwNp6X0xqrbEY2epfIWyxtC1qSNM8eD6/LQ/SahcQi2ByXa/2Aaa
|
||||
# [ide]
|
||||
DEVTOOL_IDE=phpstorm
|
||||
|
||||
DB_DRIVER=mysql
|
||||
DB_HOST=s2.gnip.vip
|
||||
DB_PORT=20191
|
||||
DB_DATABASE=mineadmin
|
||||
DB_USERNAME=hhl
|
||||
DB_PASSWORD=hhltest
|
||||
DB_HOST=127.0.0.1
|
||||
DB_PORT=3306
|
||||
DB_DATABASE=xxx
|
||||
DB_USERNAME=username
|
||||
DB_PASSWORD=password
|
||||
DB_CHARSET=utf8mb4
|
||||
DB_COLLATION=utf8mb4_unicode_ci
|
||||
DB_PREFIX=
|
||||
|
||||
REDIS_HOST=s2.gnip.vip
|
||||
REDIS_AUTH=hhltest
|
||||
REDIS_PORT=4379
|
||||
REDIS_HOST=127.0.0.1
|
||||
REDIS_AUTH=
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
223
README.md
223
README.md
@@ -1,6 +1,6 @@
|
||||
## 仓库
|
||||
|
||||
- [sfyy_server](https://codeup.aliyun.com/67039465d8d1ada68263f984/hhl/rewrite/hyperf_service.git) - git远程仓库地址
|
||||
- [hyperf_rbac_framework_server_ctexthuang](https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git) - git远程仓库地址
|
||||
|
||||
## 特性
|
||||
|
||||
@@ -27,9 +27,7 @@
|
||||
- 获取代码
|
||||
|
||||
```bash
|
||||
git clone https://codeup.aliyun.com/67039465d8d1ada68263f984/hhl/rewrite/hyperf_service.git
|
||||
|
||||
mkdir uploads
|
||||
git clone https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git
|
||||
```
|
||||
|
||||
- vendor
|
||||
@@ -50,22 +48,32 @@ php bin/hyperf.php start
|
||||
|
||||
- command 函数
|
||||
```bash
|
||||
#框架自有
|
||||
php bin/hyperf.php gen:controller LoginController
|
||||
php bin/hyperf.php gen:model UserModel
|
||||
php bin/hyperf.php gen:request LoginRequest
|
||||
php bin/hyperf.php gen:command TestCommand
|
||||
php bin/hyperf.php gen:job TestJob
|
||||
php bin/hyperf.php gen:listener TestListener
|
||||
php bin/hyperf.php gen:middleware AuthMiddleware
|
||||
php bin/hyperf.php gen:amqp-consumer DemoConsumer
|
||||
php bin/hyperf.php gen:amqp-producer DemoProducer
|
||||
php bin/hyperf.php gen:constant ErrorCode --type enum
|
||||
#框架自有 php bin/hyperf.php + 以下
|
||||
gen:amqp-consumer Create a new amqp consumer class
|
||||
gen:amqp-producer Create a new amqp producer class
|
||||
gen:aspect Create a new aspect class
|
||||
gen:class Create a new class
|
||||
gen:command Create a new command class
|
||||
gen:constant Create a new constant class
|
||||
gen:controller Create a new controller class
|
||||
gen:job Create a new job class
|
||||
gen:kafka-consumer Create a new kafka consumer class
|
||||
gen:listener Create a new listener class
|
||||
gen:middleware Create a new middleware class
|
||||
gen:migration Generate a new migration file
|
||||
gen:model Create new model classes.
|
||||
gen:nats-consumer Create a new nats consumer class
|
||||
gen:nsq-consumer Create a new nsq consumer class
|
||||
gen:process Create a new process class
|
||||
gen:repository Create a new repository class
|
||||
gen:request Create a new form request class
|
||||
gen:resource create a new resource
|
||||
gen:seeder Create a new seeder class
|
||||
gen:service Create a new service class
|
||||
|
||||
#新增命令
|
||||
php bin/hyperf.php gen:service LoginService
|
||||
php bin/hyperf.php gen:cron OssTask
|
||||
php bin/hyperf.php gen:event TestEvent
|
||||
php bin/hyperf.php gen:repository OssRepository
|
||||
```
|
||||
|
||||
## Git 贡献提交规范
|
||||
@@ -86,9 +94,6 @@ php bin/hyperf.php gen:event TestEvent
|
||||
- `wip` 开发中
|
||||
- `types` 类型
|
||||
|
||||
## cache
|
||||
不允许使用序列化,为跨语言做准备
|
||||
|
||||
## 日志(合理安排)
|
||||
| 分组名称 | 用途 | 日志级别 | 保留天数 | 备注 |
|
||||
|---------|---------|------------|------|----------|
|
||||
@@ -98,4 +103,180 @@ php bin/hyperf.php gen:event TestEvent
|
||||
| request | 请求访问日志 | INFO | 15 | 记录所有请求 |
|
||||
| cron | 定时任务日志 | INFO | 30 | 定时任务执行记录 |
|
||||
| payment | 支付相关日志 | INFO | 90 | 重要财务数据 |
|
||||
| audit | 审计日志 | INFO | 365 | 重要操作记录 |
|
||||
| audit | 审计日志 | INFO | 365 | 重要操作记录 |\
|
||||
|
||||
```php
|
||||
//注入这个类
|
||||
use App\Lib\Log\Logger;
|
||||
|
||||
$this->logger->cache()->error(...),
|
||||
```
|
||||
|
||||
## 缓存
|
||||
```php
|
||||
//注入这个类
|
||||
use App\Cache\Redis\RedisCache
|
||||
|
||||
$this->redis->with($poolName)->exists($key)
|
||||
//$poolName 配置在 config/autoload/redis.php 在 default下面追加即可 看官网
|
||||
|
||||
//lua调用涉及多文件请看示例
|
||||
|
||||
$this->redis->with($poolName ?? 'default')->lua(RateLimit::class)->check($argument);
|
||||
//lua()里面是App\Cache\Redis\Lua\*文件 后面跟的方法是 该文件的方法
|
||||
//我做了返回类型补全 可以直接IDE跳转查看参数
|
||||
```
|
||||
|
||||
## tips
|
||||
|
||||
1.AdminService类必须继承BaseAdminService
|
||||
```php
|
||||
//例子 app/Service/Admin/AdminUser/UserService
|
||||
class UserService extends \App\Service\Admin\BaseAdminService {
|
||||
|
||||
}
|
||||
|
||||
//由于在 app/Controller/Admin/AdminUserController 中 service 是 注解注入的 所以 BaseAdminService只会实例化一次(单例)
|
||||
class AdminUserController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var UserService
|
||||
*/
|
||||
#[Inject]
|
||||
protected UserService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "getInfo", methods: "GET")]
|
||||
public function getInfo(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
}
|
||||
|
||||
//所以在service中获取上下文的数据必须重置获取而不能存入BaseService属性中拿取
|
||||
//假设在 Api目录中写 BaseApiService请务必注意
|
||||
class UserService extends \App\Service\Admin\BaseAdminService {
|
||||
/**
|
||||
* @param string $name
|
||||
* @return \current_admin_id|mixed
|
||||
*/
|
||||
public function __get(string $name)
|
||||
{
|
||||
if ($name === 'adminId') return Context::get('current_admin_id',0);
|
||||
|
||||
if (!property_exists($this, $name)) throw new ErrException('属性未定义');
|
||||
|
||||
return $this->$name;
|
||||
}
|
||||
}
|
||||
|
||||
class UserService extends BaseAdminService{
|
||||
public function handle()
|
||||
{
|
||||
return $this->adminId;
|
||||
}
|
||||
}
|
||||
// 或者在controller中实例化去调用
|
||||
class AdminUserController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "getInfo", methods: "GET")]
|
||||
public function getInfo(): array
|
||||
{
|
||||
return (new UserService)->handle();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2.controller必须增加ResponseFormat注解
|
||||
```php
|
||||
//示例 : app/Controller/Admin/AdminUserController
|
||||
|
||||
#[Controller(prefix: "admin/adminUser")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminUserController extends \App\Controller\AbstractController{
|
||||
|
||||
}
|
||||
|
||||
//因为在涉及到公有抛出 ErrException或者 验证器抛出 的时候 会根据不同的注解 返回不同的 Return
|
||||
class BaseErrExceptionHandler extends ExceptionHandler{
|
||||
public function handle()
|
||||
{
|
||||
// 从注解获取响应格式(优先于路径解析)
|
||||
$format = $this->request->getAttribute('response_format') ?? $this->repairResponseFormatByPath();
|
||||
|
||||
// 动态选择策略
|
||||
$returnClass = match ($format) {
|
||||
'admin', 'common' => AdminReturn::class,
|
||||
'api' => ApiReturn::class,
|
||||
default => null,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
// 通过切面存入
|
||||
class ResponseFormatAspect extends AbstractAspect
|
||||
{
|
||||
// 获取注解定义的格式
|
||||
$annotation = $proceedingJoinPoint->getAnnotationMetadata()->class[ResponseFormat::class]
|
||||
?? $proceedingJoinPoint->getAnnotationMetadata()->method[ResponseFormat::class] ?? null;
|
||||
|
||||
if ($annotation) {
|
||||
// 将注解格式存入请求属性(覆盖中间件的默认值)
|
||||
$request = $proceedingJoinPoint->arguments['request'] ?? null;
|
||||
if ($request instanceof Request) {
|
||||
$request->withAttribute('response_format', $annotation->format);
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
3.token的使用要分模块
|
||||
```php
|
||||
//示例 app/Service/Admin/Login/LoginService
|
||||
use App\Service\BaseTokenService $tokenService
|
||||
|
||||
class LoginService extends \App\Service\Admin\BaseAdminService{
|
||||
public function handle()
|
||||
{
|
||||
$jwtHandle = $this->tokenService->setJwt('admin')->getJwt();
|
||||
|
||||
return $this->adminReturn->success('success',[
|
||||
'access_token' => $jwtHandle->builderAccessToken((string) $adminInfo->id)->toString(),
|
||||
'refresh_token' => $jwtHandle->builderRefreshToken((string) $adminInfo->id)->toString(),
|
||||
'expire_at' => (int) $jwtHandle->getConfig('ttl', 0),
|
||||
]);
|
||||
}
|
||||
}
|
||||
//setJwt函数里面类似$poolName 设置在 config/autoload/jwt.php 未设置属性可复用 default 设置
|
||||
```
|
||||
|
||||
4.引入 Repository层架构 解放 model层压力 model 只管理数据模型和关联
|
||||
```php
|
||||
//详细请看app/Common/Repository 文件下的文件 示例 app/Service/Admin/Login/LoginService
|
||||
|
||||
class LoginService extends \App\Service\Admin\BaseAdminService{
|
||||
|
||||
/**
|
||||
* 需要提前注入
|
||||
* @var AdminUserRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminUserRepository $userRepository;
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$adminInfo = $this->userRepository->findByUserName((string)$this->request->input('username'));
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
5.公用类都在 app/Common 下面 包括 `Interface`、`Macros`、`Repository`、`Trait`
|
||||
|
||||
6.后台权限注解 #[Permission] 和 #[PermissionMiddleware]
|
||||
115
app/Aspect/AdminLoginLogAspect.php
Normal file
115
app/Aspect/AdminLoginLogAspect.php
Normal file
@@ -0,0 +1,115 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Aspect;
|
||||
|
||||
use App\Common\Repository\AdminUserRepository;
|
||||
use App\Common\Trait\ClientIpTrait;
|
||||
use App\Common\Trait\ClientOsTrait;
|
||||
use App\Lib\Log\Logger;
|
||||
use App\Model\AdminUserLoginLog;
|
||||
use App\Service\Admin\Login\LoginService;
|
||||
use Hyperf\Coroutine\Coroutine;
|
||||
use Hyperf\Di\Annotation\Aspect;
|
||||
use Hyperf\Di\Aop\AbstractAspect;
|
||||
use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
use Hyperf\Di\Exception\Exception;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Throwable;
|
||||
|
||||
#[Aspect]
|
||||
class AdminLoginLogAspect extends AbstractAspect
|
||||
{
|
||||
use ClientIpTrait;
|
||||
use ClientOsTrait;
|
||||
|
||||
/**
|
||||
* 切入类
|
||||
* @var array|\class-string[]
|
||||
*/
|
||||
public array $classes = [
|
||||
LoginService::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $loginSuccess = false;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
private string $loginMsg = '';
|
||||
|
||||
/**
|
||||
* @param Logger $logger
|
||||
* @param RequestInterface $request
|
||||
* @param AdminUserRepository $adminUserRepository
|
||||
* @param AdminUserLoginLog $adminUserLoginLogModel
|
||||
*/
|
||||
public function __construct(
|
||||
protected readonly Logger $logger,
|
||||
protected RequestInterface $request,
|
||||
protected readonly AdminUserRepository $adminUserRepository,
|
||||
protected readonly AdminUserLoginLog $adminUserLoginLogModel,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @param ProceedingJoinPoint $proceedingJoinPoint
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
* @throws Throwable
|
||||
*/
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint): mixed
|
||||
{
|
||||
// 写日志
|
||||
|
||||
try {
|
||||
$res = $proceedingJoinPoint->process();
|
||||
$this->loginSuccess = true;
|
||||
$this->loginMsg = 'success';
|
||||
} catch (Throwable $throwable) {
|
||||
$this->loginSuccess = false;
|
||||
$this->loginMsg = $throwable->getMessage();
|
||||
throw $throwable;
|
||||
} finally {
|
||||
$this->writeLoginLog();
|
||||
}
|
||||
|
||||
// 返回
|
||||
return $res;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
private function writeLoginLog(): void
|
||||
{
|
||||
$userInfo = $this->adminUserRepository->findByUserName($this->request->input('username'));
|
||||
|
||||
$context = [
|
||||
'username' => $this->request->input('username',''),
|
||||
'password' => $this->request->input('password',''),
|
||||
'user_info' => $userInfo?->toArray() ?? [],
|
||||
'ip' => $this->getClientIp(),
|
||||
'os' => $this->getClientOs(),
|
||||
'browser' => $this->request->header('User-Agent') ?: 'unknown',
|
||||
];
|
||||
|
||||
Coroutine::create(function () use ($userInfo, $context) {
|
||||
$this->logger->request()->info('admin_login_log', $context);
|
||||
|
||||
$this->adminUserLoginLogModel->create([
|
||||
'admin_user_id' => $userInfo?->id ?? 0,
|
||||
'username' => $userInfo?->username ?? '',
|
||||
'ip' => current($context['ip']) ?: '0.0.0.0',
|
||||
'os' => $context['os'],
|
||||
'browser' => $context['browser'] ?? '',
|
||||
'status' => $this->loginSuccess ? 1 : 2,
|
||||
'message' => $this->loginMsg,
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
111
app/Aspect/AdminReturnLogAspect.php
Normal file
111
app/Aspect/AdminReturnLogAspect.php
Normal file
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Aspect;
|
||||
|
||||
use App\Common\Trait\AdminUserTrait;
|
||||
use App\Common\Trait\ClientIpTrait;
|
||||
use App\Lib\Log\Logger;
|
||||
use App\Lib\Return\AdminReturn;
|
||||
use App\Model\AdminUser;
|
||||
use App\Model\AdminUserOperationLog;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\Coroutine\Coroutine;
|
||||
use Hyperf\Di\Annotation\Aspect;
|
||||
use Hyperf\Di\Aop\AbstractAspect;
|
||||
use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
use Hyperf\Di\Exception\Exception;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
#[Aspect]
|
||||
class AdminReturnLogAspect extends AbstractAspect
|
||||
{
|
||||
use ClientIpTrait;
|
||||
use AdminUserTrait;
|
||||
|
||||
/**
|
||||
* 切入类
|
||||
* @var array|\class-string[]
|
||||
*/
|
||||
public array $classes = [
|
||||
AdminReturn::class,
|
||||
];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected int $adminId = 0;
|
||||
|
||||
/**
|
||||
* @var ?AdminUser
|
||||
*/
|
||||
protected ?AdminUser $adminUserInfo = null;
|
||||
|
||||
/**
|
||||
* @param Logger $logger
|
||||
* @param RequestInterface $request
|
||||
* @param AdminUserOperationLog $adminUserOperationLogModel
|
||||
*/
|
||||
public function __construct(
|
||||
protected readonly Logger $logger,
|
||||
protected RequestInterface $request,
|
||||
protected readonly AdminUserOperationLog $adminUserOperationLogModel,
|
||||
) {
|
||||
$this->adminId = Context::get('current_admin_id',0);
|
||||
if ($this->adminId > 0) $this->adminUserInfo = $this->getAdminUserInfo($this->adminId);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param ProceedingJoinPoint $proceedingJoinPoint
|
||||
* @return mixed
|
||||
* @throws Exception
|
||||
*/
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint)
|
||||
{
|
||||
// 直接从方法参数获取请求数据
|
||||
$requestData = $proceedingJoinPoint->getArguments()[0] ?? [];
|
||||
|
||||
// 执行原方法并获取返回值
|
||||
$responseData = $proceedingJoinPoint->process();
|
||||
|
||||
// 没登录不记录日志
|
||||
if ($this->adminId <= 0) return $responseData;
|
||||
|
||||
// 写日志
|
||||
$this->writeOperationLog($requestData, $responseData);
|
||||
|
||||
// 返回
|
||||
return $responseData;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $requestData
|
||||
* @param array $responseData
|
||||
* @return void
|
||||
*/
|
||||
private function writeOperationLog(array $requestData = [], array $responseData = []): void
|
||||
{
|
||||
$context = [
|
||||
'user_id' => $this->adminId,
|
||||
'method' => $this->request->getMethod(),
|
||||
'router' => $this->request->getUri(),
|
||||
'ip' => $this->getClientIp(),
|
||||
'request_data' => $requestData,
|
||||
'response_data' => $responseData,
|
||||
];
|
||||
|
||||
Coroutine::create(function () use ($requestData, $responseData, $context) {
|
||||
$this->logger->request()->info('admin_request_log', $context);
|
||||
|
||||
$this->adminUserOperationLogModel->create([
|
||||
'admin_user_id' => $this->adminId,
|
||||
'username' => $this->adminUserInfo?->username ?? '',
|
||||
'method' => $context['method'],
|
||||
'router' => $context['router'],
|
||||
'service_name' => $context['service_name'] ?? '',
|
||||
'ip' => current($context['ip']) ?: '0.0.0.0',
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -163,7 +163,7 @@ abstract class BaseScript
|
||||
];
|
||||
|
||||
$logStrategy = match(true) {
|
||||
!$success => $this->logger->cache()->error(...),
|
||||
!$success => $this->logger->error()->error(...),
|
||||
$this->debugMode => $this->logger->cache()->debug(...),
|
||||
default => fn() => null // 不记录
|
||||
};
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Cache\Redis;
|
||||
|
||||
use App\Cache\Redis\Lua\RateLimit;
|
||||
use App\Lib\Log\Logger;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use Hyperf\Redis\RedisFactory;
|
||||
@@ -9,6 +10,7 @@ use Hyperf\Redis\RedisProxy;
|
||||
|
||||
/**
|
||||
* @mixin RedisProxy
|
||||
* @template T
|
||||
*/
|
||||
class RedisCache
|
||||
{
|
||||
@@ -53,10 +55,11 @@ class RedisCache
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scriptClass
|
||||
* @return mixed
|
||||
* @template TReturn
|
||||
* @param class-string<TReturn> $scriptClass
|
||||
* @return TReturn
|
||||
*/
|
||||
public function lua(string $scriptClass): mixed
|
||||
public function lua(string $scriptClass)
|
||||
{
|
||||
$poolName = $this->poolName ?? 'default';
|
||||
$key = $poolName . ':' . $scriptClass;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interface;
|
||||
namespace App\Common\Interface;
|
||||
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Interface;
|
||||
namespace App\Common\Interface;
|
||||
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
|
||||
80
app/Common/Repository/AdminMenuRepository.php
Normal file
80
app/Common/Repository/AdminMenuRepository.php
Normal file
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Constants\Model\AdminUser\AdminMenuStatusCode;
|
||||
use App\Model\AdminMenu;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Collection\Collection;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
|
||||
final class AdminMenuRepository extends BaseRepository
|
||||
{
|
||||
/**
|
||||
* @param AdminMenu $model
|
||||
*/
|
||||
public function __construct(protected readonly AdminMenu $model) {}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function enablePageOrderBy(): bool
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $params
|
||||
* @return Collection
|
||||
*/
|
||||
public function list(array $params = []): Collection
|
||||
{
|
||||
return $this->perQuery($this->getQuery(), $params)->orderBy('sort')->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param array $params
|
||||
* @return Builder
|
||||
*/
|
||||
public function handleSearch(Builder $query, array $params): Builder
|
||||
{
|
||||
$whereInName = static function (Builder $query, array|string $code) {
|
||||
$query->whereIn('name', Arr::wrap($code));
|
||||
};
|
||||
return $query
|
||||
->when(Arr::get($params, 'sortable'), static function (Builder $query, array $sortable) {
|
||||
$query->orderBy(key($sortable), current($sortable));
|
||||
})
|
||||
->when(Arr::get($params, 'code'), $whereInName)
|
||||
->when(Arr::get($params, 'name'), $whereInName)
|
||||
->when(Arr::get($params, 'children'), static function (Builder $query) {
|
||||
$query->with('children');
|
||||
})->when(Arr::get($params, 'status'), static function (Builder $query, AdminMenuStatusCode $status) {
|
||||
$query->where('status', $status);
|
||||
})
|
||||
->when(Arr::has($params, 'parent_id'), static function (Builder $query) use ($params) {
|
||||
$query->where('parent_id', Arr::get($params, 'parent_id'));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Builder[]|\Hyperf\Database\Model\Collection
|
||||
*/
|
||||
public function allTree(): \Hyperf\Database\Model\Collection|array
|
||||
{
|
||||
return $this->model
|
||||
->newQuery()
|
||||
->where('parent_id', 0)
|
||||
->with('children')
|
||||
->get();
|
||||
}
|
||||
}
|
||||
38
app/Common/Repository/AdminRoleRepository.php
Normal file
38
app/Common/Repository/AdminRoleRepository.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Model\AdminRole;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
|
||||
final class AdminRoleRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(protected readonly AdminRole $model) {}
|
||||
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param array $params
|
||||
* @return Builder
|
||||
*/
|
||||
public function handleSearch(Builder $query, array $params): Builder
|
||||
{
|
||||
return $query->when(Arr::get($params, 'name'), static function (Builder $query, $name) {
|
||||
$query->where('name', 'like', '%' . $name . '%');
|
||||
})->when(Arr::get($params, 'code'), static function (Builder $query, $code) {
|
||||
$query->whereIn('code', Arr::wrap($code));
|
||||
})->when(Arr::has($params, 'status'), static function (Builder $query) use ($params) {
|
||||
$query->where('status', $params['status']);
|
||||
})->when(Arr::get($params, 'created_at'), static function (Builder $query, $createdAt) {
|
||||
$query->whereBetween('created_at', $createdAt);
|
||||
});
|
||||
}
|
||||
}
|
||||
57
app/Common/Repository/AdminUserLoginLogRepository.php
Normal file
57
app/Common/Repository/AdminUserLoginLogRepository.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Model\AdminUserLoginLog;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
|
||||
final class AdminUserLoginLogRepository extends BaseRepository
|
||||
{
|
||||
/**
|
||||
* @param AdminUserLoginLog $model
|
||||
*/
|
||||
public function __construct(protected readonly AdminUserLoginLog $model) {}
|
||||
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param array $params
|
||||
* @return Builder
|
||||
*/
|
||||
public function handleSearch(Builder $query, array $params): Builder
|
||||
{
|
||||
return $query
|
||||
->when(Arr::get($params, 'username'), static function (Builder $query, $username) {
|
||||
$query->where('username', $username);
|
||||
})
|
||||
->when(Arr::get($params, 'ip'), static function (Builder $query, $ip) {
|
||||
$query->where('ip', $ip);
|
||||
})
|
||||
->when(Arr::get($params, 'os'), static function (Builder $query, $os) {
|
||||
$query->where('os', $os);
|
||||
})
|
||||
->when(Arr::get($params, 'browser'), static function (Builder $query, $browser) {
|
||||
$query->where('browser', $browser);
|
||||
})
|
||||
->when(Arr::get($params, 'status'), static function (Builder $query, $status) {
|
||||
$query->where('status', $status);
|
||||
})
|
||||
->when(Arr::get($params, 'message'), static function (Builder $query, $message) {
|
||||
$query->where('message', $message);
|
||||
})
|
||||
->when(Arr::get($params, 'login_time'), static function (Builder $query, $login_time) {
|
||||
$query->whereBetween('login_time', $login_time);
|
||||
})
|
||||
->when(Arr::get($params, 'remark'), static function (Builder $query, $remark) {
|
||||
$query->where('remark', $remark);
|
||||
});
|
||||
}
|
||||
}
|
||||
18
app/Common/Repository/AdminUserOperationLogRepository.php
Normal file
18
app/Common/Repository/AdminUserOperationLogRepository.php
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Model\AdminUserOperationLog;
|
||||
|
||||
final class AdminUserOperationLogRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(protected readonly AdminUserOperationLog $model) {}
|
||||
}
|
||||
81
app/Common/Repository/AdminUserRepository.php
Normal file
81
app/Common/Repository/AdminUserRepository.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Model\AdminUser;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
|
||||
/**
|
||||
* Class AdminUserRepository
|
||||
* @extends BaseRepository<AdminUser>
|
||||
*/
|
||||
final class AdminUserRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(protected readonly AdminUser $model) {}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @return AdminUser|null
|
||||
*/
|
||||
public function findByUserName(string $username): AdminUser|null
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->model->newQuery()
|
||||
->where('username', $username)
|
||||
->first();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @param array $params
|
||||
* @return Builder
|
||||
*/
|
||||
public function handleSearch(Builder $query, array $params): Builder
|
||||
{
|
||||
return $query
|
||||
->when(Arr::get($params, 'unique_username'), static function (Builder $query, $uniqueUsername) {
|
||||
$query->where('username', $uniqueUsername);
|
||||
})
|
||||
->when(Arr::get($params, 'username'), static function (Builder $query, $username) {
|
||||
$query->where('username', 'like', '%' . $username . '%');
|
||||
})
|
||||
->when(Arr::get($params, 'phone'), static function (Builder $query, $phone) {
|
||||
$query->where('phone', $phone);
|
||||
})
|
||||
->when(Arr::get($params, 'email'), static function (Builder $query, $email) {
|
||||
$query->where('email', $email);
|
||||
})
|
||||
->when(Arr::exists($params, 'status'), static function (Builder $query) use ($params) {
|
||||
$query->where('status', Arr::get($params, 'status'));
|
||||
})
|
||||
->when(Arr::exists($params, 'user_type'), static function (Builder $query) use ($params) {
|
||||
$query->where('user_type', Arr::get($params, 'user_type'));
|
||||
})
|
||||
->when(Arr::exists($params, 'nickname'), static function (Builder $query) use ($params) {
|
||||
$query->where('nickname', 'like', '%' . Arr::get($params, 'nickname') . '%');
|
||||
})
|
||||
->when(Arr::exists($params, 'created_at'), static function (Builder $query) use ($params) {
|
||||
$query->whereBetween('created_at', [
|
||||
Arr::get($params, 'created_at')[0] . ' 00:00:00',
|
||||
Arr::get($params, 'created_at')[1] . ' 23:59:59',
|
||||
]);
|
||||
})
|
||||
->when(Arr::get($params, 'user_ids'), static function (Builder $query, $userIds) {
|
||||
$query->whereIn('id', $userIds);
|
||||
})
|
||||
->when(Arr::get($params, 'role_id'), static function (Builder $query, $roleId) {
|
||||
$query->whereHas('roles', static function (Builder $query) use ($roleId) {
|
||||
$query->where('role_id', $roleId);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -1,9 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository;
|
||||
namespace App\Common\Repository;
|
||||
|
||||
use App\Repository\Traits\BootTrait;
|
||||
use App\Repository\Traits\RepositoryOrderByTrait;
|
||||
use App\Common\Repository\Traits\BootTrait;
|
||||
use App\Common\Repository\Traits\RepositoryOrderByTrait;
|
||||
use Hyperf\Collection\Collection;
|
||||
use Hyperf\Contract\LengthAwarePaginatorInterface;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
@@ -13,7 +13,7 @@ use Hyperf\Paginator\AbstractPaginator;
|
||||
|
||||
/**
|
||||
* @template T of Model
|
||||
* @property T $model
|
||||
* @property Model $model
|
||||
*/
|
||||
abstract class BaseRepository
|
||||
{
|
||||
@@ -67,7 +67,7 @@ abstract class BaseRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @return T
|
||||
* @return Model
|
||||
*/
|
||||
public function create(array $data): mixed
|
||||
{
|
||||
@@ -81,7 +81,7 @@ abstract class BaseRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|T
|
||||
* @return null|Model
|
||||
*/
|
||||
public function saveById(mixed $id, array $data): mixed
|
||||
{
|
||||
@@ -105,7 +105,7 @@ abstract class BaseRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|T
|
||||
* @return null|Model
|
||||
*/
|
||||
public function findById(mixed $id): mixed
|
||||
{
|
||||
@@ -118,7 +118,7 @@ abstract class BaseRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null|T
|
||||
* @return null|Model
|
||||
*/
|
||||
public function findByFilter(array $params): mixed
|
||||
{
|
||||
@@ -142,7 +142,7 @@ abstract class BaseRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* @return T
|
||||
* @return Model
|
||||
*/
|
||||
public function getModel(): Model
|
||||
{
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Traits;
|
||||
namespace App\Common\Repository\Traits;
|
||||
|
||||
use function Hyperf\Support\class_basename;
|
||||
use function Hyperf\Support\class_uses_recursive;
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
namespace App\Repository\Traits;
|
||||
namespace App\Common\Repository\Traits;
|
||||
|
||||
use Hyperf\Database\Model\Builder;
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
<?php
|
||||
|
||||
namespace App\Trait;
|
||||
namespace App\Common\Trait;
|
||||
|
||||
use App\Cache\Redis\Lua\RateLimit;
|
||||
use App\Cache\Redis\RedisCache;
|
||||
use App\Cache\Redis\RedisKey;
|
||||
use App\Repository\AdminUserRepository;
|
||||
use App\Common\Repository\AdminUserRepository;
|
||||
use App\Model\AdminUser;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\Database\Model\Model;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
trait AdminUserTrait
|
||||
@@ -23,10 +26,11 @@ trait AdminUserTrait
|
||||
protected AdminUserRepository $adminUserRepository;
|
||||
|
||||
/**
|
||||
* 单例加缓存模型(仅仅用户信息) tips: 只可读取显示的数据(不影响大致问题),不可操作类敏感数据 比如 inc 账户余额 之类的 会导致脏读
|
||||
* @param int $adminId
|
||||
* @return array|null
|
||||
* @return AdminUser|Model|mixed|string|null
|
||||
*/
|
||||
public function getAdminUserInfo(int $adminId): array|null
|
||||
public function getAdminUserInfo(int $adminId): mixed
|
||||
{
|
||||
$key = RedisKey::getAdminUserInfoKey($adminId);
|
||||
if (Context::has($key)) {
|
||||
@@ -34,16 +38,16 @@ trait AdminUserTrait
|
||||
}
|
||||
|
||||
if ($this->redis->with()->exists($key)) {
|
||||
$userInfo = $this->redis->with()->get($key);
|
||||
$userInfo = unserialize($this->redis->with()->get($key));
|
||||
Context::set($key,$userInfo);
|
||||
return json_decode($userInfo,true);
|
||||
return $userInfo;
|
||||
}
|
||||
|
||||
$userInfo = $this->adminUserRepository->findById($adminId)?->toArray() ?? null;
|
||||
$userInfo = $this->adminUserRepository->findById($adminId) ?? null;
|
||||
if (!$userInfo) return null;
|
||||
|
||||
Context::set($key, $userInfo);
|
||||
$this->redis->with()->set($key, json_encode($userInfo), 3600);
|
||||
$this->redis->with()->set($key, serialize($userInfo), 3600);
|
||||
|
||||
return $userInfo;
|
||||
}
|
||||
192
app/Common/Trait/ClientIpTrait.php
Normal file
192
app/Common/Trait/ClientIpTrait.php
Normal file
@@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
namespace App\Common\Trait;
|
||||
|
||||
use App\Constants\Common\ClientIpRequestConstant;
|
||||
use App\Exception\ErrException;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Symfony\Component\HttpFoundation\HeaderUtils;
|
||||
use Symfony\Component\HttpFoundation\IpUtils;
|
||||
|
||||
trait ClientIpTrait
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
#[Inject]
|
||||
protected RequestInterface $request;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected static array $trustedProxies = [];
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private static int $trustedHeaderSet = -1;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private array $trustedValuesCache = [];
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private bool $isForwardedValid = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private static bool $isTrustedRemoteAddr = false;
|
||||
|
||||
/**
|
||||
* 设置可信代理
|
||||
* @return bool
|
||||
*/
|
||||
public static function isTrustedRemoteAddr(): bool
|
||||
{
|
||||
return self::$isTrustedRemoteAddr;
|
||||
}
|
||||
|
||||
/**
|
||||
* 返回客户端IP地址。
|
||||
* 在返回的数组中,最可信的IP地址排在第一位,最不可信的IP地址排在最后。“真正的”客户端IP地址是最后一个,但这也是最不可信的一个。可信代理被剥离。
|
||||
* @return array
|
||||
*/
|
||||
public function getClientIp(): array
|
||||
{
|
||||
$ip = $this->request->server('remote_addr');
|
||||
|
||||
if (! $this->isFromTrustedProxy()) return [$ip];
|
||||
|
||||
return $this->getTrustedValues(ClientIpRequestConstant::HEADER_X_FORWARDED_FOR, $ip) ?: [$ip];
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断此请求是否来自受信任的代理。这可以用于确定是否信任
|
||||
* @return bool
|
||||
*/
|
||||
private function isFromTrustedProxy(): bool
|
||||
{
|
||||
return (
|
||||
self::$trustedProxies &&
|
||||
IpUtils::checkIp($this->request->server('remote_addr',''),self::$trustedProxies) ||
|
||||
self::isTrustedRemoteAddr()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $type
|
||||
* @param string|null $ip
|
||||
* @return array|mixed|null[]|string[]
|
||||
*/
|
||||
private function getTrustedValues(int $type, ?string $ip = null): mixed
|
||||
{
|
||||
$cacheKey = $type . "\0" . ((self::$trustedHeaderSet & $type) ? $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[$type]) : '');
|
||||
$cacheKey .= "\0" . $ip . "\0" . $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED]);
|
||||
|
||||
if (isset($this->trustedValuesCache[$cacheKey])) return $this->trustedValuesCache[$cacheKey];
|
||||
|
||||
$clientValues = [];
|
||||
$forwardedValues = [];
|
||||
|
||||
if (
|
||||
(self::$trustedHeaderSet & $type) &&
|
||||
$this->request->hasHeader(ClientIpRequestConstant::TRUSTED_HEADERS[$type])
|
||||
) {
|
||||
foreach (explode(',', $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[$type])) as $value) {
|
||||
$clientValues[] = ($type === ClientIpRequestConstant::HEADER_X_FORWARDED_PORT ? '0.0.0.0' : trim($value));
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
(self::$trustedHeaderSet & ClientIpRequestConstant::HEADER_FORWARDED) &&
|
||||
(isset(ClientIpRequestConstant::FORWARDED_PARAMS[$type])) &&
|
||||
$this->request->hasHeader(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED])
|
||||
) {
|
||||
$forward = $this->request->getHeaderLine(ClientIpRequestConstant::TRUSTED_HEADERS[ClientIpRequestConstant::HEADER_FORWARDED]);
|
||||
$parts = HeaderUtils::split($forward, ',;=');
|
||||
$param = ClientIpRequestConstant::FORWARDED_PARAMS[$type];
|
||||
|
||||
foreach ($parts as $subParts) {
|
||||
if (($value = HeaderUtils::combine($subParts)[$param] ?? null) === null) continue;
|
||||
|
||||
if ($type === ClientIpRequestConstant::HEADER_X_FORWARDED_PORT) {
|
||||
if (
|
||||
str_ends_with($value, ']') ||
|
||||
($value = mb_strrchr($value, ':')) === false
|
||||
) $value = $this->isSecure() ? ':443' : ':80';
|
||||
|
||||
$value = '0.0.0.0' . $value;
|
||||
}
|
||||
|
||||
$forwardedValues[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
if (null !== $ip) {
|
||||
$clientValues = $this->normalizeAndFilterClientIps($clientValues, $ip);
|
||||
$forwardedValues = $this->normalizeAndFilterClientIps($forwardedValues, $ip);
|
||||
}
|
||||
|
||||
if ($forwardedValues === $clientValues || !$clientValues) return $this->trustedValuesCache[$cacheKey] = $forwardedValues;
|
||||
|
||||
if (!$forwardedValues) return $this->trustedValuesCache[$cacheKey] = $clientValues;
|
||||
|
||||
if (!$this->isForwardedValid) return (($ip = $this->trustedValuesCache[$cacheKey]) !== null) ? ['0.0.0.0',$ip] : [];
|
||||
|
||||
$this->isForwardedValid = false;
|
||||
throw new ErrException('转发报头无效,请检查服务器配置。');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
private function isSecure(): bool
|
||||
{
|
||||
return $this->request->getHeaderLine(ClientIpRequestConstant::HEADER_X_FORWARDED_PROTO) === 'https'
|
||||
|| ($this->request->getServerParams()['https'] ?? '') === 'on';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $clientIps
|
||||
* @param string $ip
|
||||
* @return array|null[]|string[]
|
||||
*/
|
||||
private function normalizeAndFilterClientIps(array $clientIps, string $ip): array
|
||||
{
|
||||
if (!$clientIps) return [];
|
||||
|
||||
$clientIps[] = $ip;
|
||||
$firstTrustedIp = null;
|
||||
|
||||
foreach ($clientIps as $key => $clientIp) {
|
||||
if (mb_strpos($clientIp, '.')) {
|
||||
// ipv4
|
||||
$i = mb_strpos($clientIp, '.');
|
||||
|
||||
if ($i) $clientIps[$key] = $clientIp = mb_substr($clientIp, 0, $i);
|
||||
} elseif (str_starts_with($clientIp, '[')) {
|
||||
// ipv6
|
||||
$i = mb_strpos($clientIp, ']',1);
|
||||
$clientIps[$key] = $clientIp = mb_substr($clientIp, 1, $i - 1);
|
||||
}
|
||||
|
||||
if (!filter_var($clientIp, FILTER_VALIDATE_IP)) {
|
||||
unset($clientIps[$key]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IpUtils::checkIp($clientIp, self::$trustedProxies)) {
|
||||
unset($clientIps[$key]);
|
||||
|
||||
$firstTrustedIp ??= $clientIp;
|
||||
}
|
||||
}
|
||||
|
||||
return $clientIps ? array_reverse($clientIps) : [$firstTrustedIp];
|
||||
}
|
||||
}
|
||||
34
app/Common/Trait/ClientOsTrait.php
Normal file
34
app/Common/Trait/ClientOsTrait.php
Normal file
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace App\Common\Trait;
|
||||
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
trait ClientOsTrait
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
#[Inject]
|
||||
protected RequestInterface $request;
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getClientOs(): string
|
||||
{
|
||||
$userAgent = $this->request->header('user-agent');
|
||||
|
||||
if (empty($userAgent)) return 'Unknown';
|
||||
|
||||
return match (true) {
|
||||
preg_match('/win/i', $userAgent) => 'Windows',
|
||||
preg_match('/mac/i', $userAgent) => 'MAC',
|
||||
preg_match('/linux/i', $userAgent) => 'Linux',
|
||||
preg_match('/unix/i', $userAgent) => 'Unix',
|
||||
preg_match('/bsd/i', $userAgent) => 'BSD',
|
||||
default => 'Other',
|
||||
};
|
||||
}
|
||||
}
|
||||
47
app/Common/Trait/HttpMethodTrait.php
Normal file
47
app/Common/Trait/HttpMethodTrait.php
Normal file
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace App\Common\Trait;
|
||||
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
trait HttpMethodTrait
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
#[Inject]
|
||||
protected readonly RequestInterface $request;
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isCreate(): bool
|
||||
{
|
||||
return $this->request->isMethod('POST');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isUpdate(): bool
|
||||
{
|
||||
return $this->request->isMethod('PATCH') || $this->request->isMethod('PUT');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isDelete(): bool
|
||||
{
|
||||
return $this->request->isMethod('DELETE');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isSearch(): bool
|
||||
{
|
||||
return $this->request->isMethod('GET');
|
||||
}
|
||||
}
|
||||
25
app/Common/Trait/ParserRouterTrait.php
Normal file
25
app/Common/Trait/ParserRouterTrait.php
Normal file
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Common\Trait;
|
||||
|
||||
trait ParserRouterTrait
|
||||
{
|
||||
/**
|
||||
* @param $callback
|
||||
* @return array|string[]|null
|
||||
*/
|
||||
final protected function parse($callback): ?array
|
||||
{
|
||||
if (is_array($callback) && count($callback) == 2) return $callback;
|
||||
|
||||
if (is_string($callback)) {
|
||||
if (str_contains($callback, '@')) $explode = explode('@', $callback);
|
||||
|
||||
if (str_contains($callback, '::')) $explode = explode('::', $callback);
|
||||
|
||||
if (isset($explode) && count($explode) === 2) return $explode;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,10 @@ use Hyperf\Constants\EnumConstantsTrait;
|
||||
#[Constants]
|
||||
final class AdminCode extends ResultCode
|
||||
{
|
||||
#[Message("登录失败")]
|
||||
public const int LOGIN_ERROR = 10001;
|
||||
#[Message("账号已禁用")]
|
||||
public const int DISABLED = 423;
|
||||
|
||||
#[Message("暂无权限")]
|
||||
public const int FORBIDDEN = 403;
|
||||
|
||||
#[Message("验证已过期")]
|
||||
public const int LOGIN_TOKEN_ERROR = 10002;
|
||||
}
|
||||
|
||||
61
app/Constants/Common/ClientIpRequestConstant.php
Normal file
61
app/Constants/Common/ClientIpRequestConstant.php
Normal file
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Constants\Common;
|
||||
|
||||
|
||||
final class ClientIpRequestConstant
|
||||
{
|
||||
/**
|
||||
* RFC 7239 标准的 Forwarded 头
|
||||
*/
|
||||
public const int HEADER_FORWARDED = 0b000001;
|
||||
|
||||
/**
|
||||
* 客户端原始 IP
|
||||
*/
|
||||
public const int HEADER_X_FORWARDED_FOR = 0b000010;
|
||||
|
||||
/**
|
||||
* 原始主机名
|
||||
*/
|
||||
public const int HEADER_X_FORWARDED_HOST = 0b000100;
|
||||
|
||||
/**
|
||||
* 原始协议 (http/https)
|
||||
*/
|
||||
public const int HEADER_X_FORWARDED_PROTO = 0b001000;
|
||||
|
||||
/**
|
||||
* 原始端口
|
||||
*/
|
||||
public const int HEADER_X_FORWARDED_PORT = 0b010000;
|
||||
|
||||
/**
|
||||
* 原始路径前缀
|
||||
*/
|
||||
public const int HEADER_X_FORWARDED_PREFIX = 0b100000;
|
||||
|
||||
/**
|
||||
* 将部分标志映射到 RFC 7239 Forwarded 头中的参数名
|
||||
*/
|
||||
public const array FORWARDED_PARAMS = [
|
||||
self::HEADER_X_FORWARDED_FOR => 'for',
|
||||
self::HEADER_X_FORWARDED_HOST => 'host',
|
||||
self::HEADER_X_FORWARDED_PROTO => 'proto',
|
||||
self::HEADER_X_FORWARDED_PORT => 'host',
|
||||
];
|
||||
|
||||
/**
|
||||
* 将标志映射到实际的 HTTP 头名称
|
||||
*/
|
||||
public const array TRUSTED_HEADERS = [
|
||||
self::HEADER_FORWARDED => 'forwarded',
|
||||
self::HEADER_X_FORWARDED_FOR => 'x-forwarded-for',
|
||||
self::HEADER_X_FORWARDED_HOST => 'x-forwarded-host',
|
||||
self::HEADER_X_FORWARDED_PROTO => 'x-forwarded-proto',
|
||||
self::HEADER_X_FORWARDED_PORT => 'x-forwarded-port',
|
||||
self::HEADER_X_FORWARDED_PREFIX => 'x-forwarded-prefix',
|
||||
];
|
||||
}
|
||||
@@ -25,4 +25,7 @@ class ResultCode extends AbstractConstants
|
||||
|
||||
#[Message("token错误")]
|
||||
final public const int JWT_ERROR = 10002;
|
||||
|
||||
#[Message("旧密码错误")]
|
||||
final public const int OLD_PASSWORD_ERROR = 10003;
|
||||
}
|
||||
|
||||
77
app/Controller/Admin/AdminMenuController.php
Normal file
77
app/Controller/Admin/AdminMenuController.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Middleware\Admin\PermissionMiddleware;
|
||||
use App\Request\Admin\AdminMenuRequest;
|
||||
use App\Service\Admin\AdminUser\MenuService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\Middleware;
|
||||
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||
use Hyperf\Validation\Annotation\Scene;
|
||||
|
||||
|
||||
#[Controller(prefix: "admin/menu")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminMenuController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var MenuService
|
||||
*/
|
||||
#[Inject]
|
||||
protected MenuService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "list", methods: "GET")]
|
||||
#[Permission(code: 'permission:menu:index')]
|
||||
public function pageList(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdminMenuRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "POST")]
|
||||
#[Permission(code: 'permission:menu:create')]
|
||||
#[Scene(scene: "create")]
|
||||
public function createMenu(AdminMenuRequest $request): array
|
||||
{
|
||||
return $this->service->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param AdminMenuRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "{id}", methods: "PUT")]
|
||||
#[Permission(code: 'permission:menu:save')]
|
||||
#[Scene(scene: "update")]
|
||||
public function updateMenu(int $id, AdminMenuRequest $request): array
|
||||
{
|
||||
return $this->service->update($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "DELETE")]
|
||||
#[Permission(code: 'permission:menu:delete')]
|
||||
public function deleteMenu(): array
|
||||
{
|
||||
return $this->service->delete();
|
||||
}
|
||||
}
|
||||
101
app/Controller/Admin/AdminRoleController.php
Normal file
101
app/Controller/Admin/AdminRoleController.php
Normal file
@@ -0,0 +1,101 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Middleware\Admin\PermissionMiddleware;
|
||||
use App\Request\Admin\AdminRoleRequest;
|
||||
use App\Service\Admin\AdminUser\RoleService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\Middleware;
|
||||
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||
use Hyperf\Validation\Annotation\Scene;
|
||||
|
||||
|
||||
#[Controller(prefix: "admin/role")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminRoleController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var RoleService
|
||||
*/
|
||||
#[Inject]
|
||||
protected RoleService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "list", methods: "GET")]
|
||||
#[Permission(code: 'permission:role:index')]
|
||||
public function pageList(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdminRoleRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "POST")]
|
||||
#[Permission(code: 'permission:role:save')]
|
||||
#[Scene(scene: "create")]
|
||||
public function createRole(AdminRoleRequest $request): array
|
||||
{
|
||||
return $this->service->create();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param AdminRoleRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "{id}", methods: "PUT")]
|
||||
#[Permission(code: 'permission:role:update')]
|
||||
#[Scene(scene: "create")]
|
||||
public function updateRole(int $id, AdminRoleRequest $request): array
|
||||
{
|
||||
return $this->service->update($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "DELETE")]
|
||||
#[Permission(code: 'permission:role:delete')]
|
||||
public function deleteRole(): array
|
||||
{
|
||||
return $this->service->delete();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "{id}/permission", methods: "GET")]
|
||||
#[Permission(code: 'permission:role:getMenu')]
|
||||
public function getRolePermission(int $id): array
|
||||
{
|
||||
return $this->service->getRole($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @param AdminRoleRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "{id}/permission", methods: "PUT")]
|
||||
#[Permission(code: 'permission:role:setMenu')]
|
||||
#[Scene(scene: "batch_grant_permission")]
|
||||
public function batchGrantPermissionByRole(int $id,AdminRoleRequest $request): array
|
||||
{
|
||||
return $this->service->setRole($id);
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,10 @@ namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Middleware\Token\AdminTokenMiddleware;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Middleware\Admin\PermissionMiddleware;
|
||||
use App\Request\Admin\AdminUserRequest;
|
||||
use App\Service\Admin\AdminUser\UserService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
@@ -17,8 +20,9 @@ use Hyperf\Validation\Annotation\Scene;
|
||||
|
||||
#[Controller(prefix: "admin/adminUser")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(AdminTokenMiddleware::class)]
|
||||
class AdminUserController
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminUserController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var UserService
|
||||
@@ -55,11 +59,13 @@ class AdminUserController
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdminUserRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "PUT")]
|
||||
#[Permission(code: 'permission:user:update')]
|
||||
public function updateInfo(): array
|
||||
#[Scene(scene: "update")]
|
||||
public function updateInfo(AdminUserRequest $request): array
|
||||
{
|
||||
return $this->service->updateInfo();
|
||||
}
|
||||
@@ -75,11 +81,13 @@ class AdminUserController
|
||||
}
|
||||
|
||||
/**
|
||||
* @param AdminUserRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "POST")]
|
||||
#[Permission(code: 'permission:user:save')]
|
||||
public function createAdminUser(): array
|
||||
#[Scene(scene: "create")]
|
||||
public function createAdminUser(AdminUserRequest $request): array
|
||||
{
|
||||
return $this->service->createUser();
|
||||
}
|
||||
@@ -96,7 +104,8 @@ class AdminUserController
|
||||
|
||||
#[RequestMapping(path: "{userId}", methods: "PUT")]
|
||||
#[Permission(code: 'permission:user:update')]
|
||||
public function saveInfo(int $userId): array
|
||||
#[Scene(scene: "update")]
|
||||
public function saveInfo(int $userId,AdminUserRequest $request): array
|
||||
{
|
||||
return $this->service->saveUser($userId);
|
||||
}
|
||||
@@ -114,11 +123,13 @@ class AdminUserController
|
||||
|
||||
/**
|
||||
* @param int $userId
|
||||
* @param AdminUserRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "{userId}/roles", methods: "PUT")]
|
||||
#[Permission(code: 'permission:user:setRole')]
|
||||
public function batchGrantRolesForAdminUser(int $userId): array
|
||||
#[Scene(scene: "batch_grant_role")]
|
||||
public function batchGrantRolesForAdminUser(int $userId,AdminUserRequest $request): array
|
||||
{
|
||||
return $this->service->batchGrantRoleForUser($userId);
|
||||
}
|
||||
|
||||
49
app/Controller/Admin/Log/AdminUserLoginLogController.php
Normal file
49
app/Controller/Admin/Log/AdminUserLoginLogController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin\Log;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Middleware\Admin\PermissionMiddleware;
|
||||
use App\Service\Admin\Log\AdminUserLoginLogService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\Middleware;
|
||||
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||
|
||||
#[Controller(prefix: "admin/user-login-log")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminUserLoginLogController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var AdminUserLoginLogService
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminUserLoginLogService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "list", methods: "GET")]
|
||||
#[Permission(code: 'log:userLogin:list')]
|
||||
public function pageList(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "DELETE")]
|
||||
#[Permission(code: 'log:userLogin:delete')]
|
||||
public function delete(): array
|
||||
{
|
||||
return $this->service->deleteLog();
|
||||
}
|
||||
}
|
||||
49
app/Controller/Admin/Log/AdminUserOperationLogController.php
Normal file
49
app/Controller/Admin/Log/AdminUserOperationLogController.php
Normal file
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin\Log;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Middleware\Admin\PermissionMiddleware;
|
||||
use App\Service\Admin\Log\AdminUserOperationLogService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\Middleware;
|
||||
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||
|
||||
#[Controller(prefix: "admin/user-operation-log")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
#[Middleware(middleware: PermissionMiddleware::class, priority: 99)]
|
||||
class AdminUserOperationLogController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var AdminUserOperationLogService
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminUserOperationLogService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "list", methods: "GET")]
|
||||
#[Permission(code: 'log:userOperation:list')]
|
||||
public function pageList(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "", methods: "DELETE")]
|
||||
#[Permission(code: 'log:userOperation:delete')]
|
||||
public function delete(): array
|
||||
{
|
||||
return $this->service->deleteLog();
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,7 @@ namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Token\RefreshAdminTokenMiddleware;
|
||||
use App\Middleware\Admin\RefreshAdminTokenMiddleware;
|
||||
use App\Request\Admin\LoginRequest;
|
||||
use App\Service\Admin\Login\LoginService;
|
||||
use App\Service\Admin\Login\RefreshService;
|
||||
|
||||
58
app/Controller/Admin/PermissionController.php
Normal file
58
app/Controller/Admin/PermissionController.php
Normal file
@@ -0,0 +1,58 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Annotation\ResponseFormat;
|
||||
use App\Controller\AbstractController;
|
||||
use App\Middleware\Admin\AdminTokenMiddleware;
|
||||
use App\Request\Admin\PermissionRequest;
|
||||
use App\Service\Admin\AdminUser\PermissionService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\Middleware;
|
||||
use Hyperf\HttpServer\Annotation\RequestMapping;
|
||||
use Hyperf\Validation\Annotation\Scene;
|
||||
|
||||
#[Controller(prefix: "admin/permission")]
|
||||
#[ResponseFormat('admin')]
|
||||
#[Middleware(middleware: AdminTokenMiddleware::class, priority: 100)]
|
||||
class PermissionController extends AbstractController
|
||||
{
|
||||
/**
|
||||
* @var PermissionService
|
||||
*/
|
||||
#[Inject]
|
||||
protected PermissionService $service;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "menus", methods: "GET")]
|
||||
public function menus(): array
|
||||
{
|
||||
return $this->service->handle();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "roles", methods: "GET")]
|
||||
public function roles(): array
|
||||
{
|
||||
return $this->service->getRoleByAdminUser();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PermissionRequest $request
|
||||
* @return array
|
||||
*/
|
||||
#[RequestMapping(path: "update", methods: "POST")]
|
||||
#[Scene(scene: "update")]
|
||||
public function update(PermissionRequest $request): array
|
||||
{
|
||||
return $this->service->update();
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,7 @@
|
||||
|
||||
namespace App\Lib\Jwt;
|
||||
|
||||
use App\Constants\ResultCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use Carbon\Carbon;
|
||||
use Hyperf\Cache\CacheManager;
|
||||
use Hyperf\Cache\Driver\DriverInterface;
|
||||
@@ -18,7 +16,6 @@ use Lcobucci\JWT\UnencryptedToken;
|
||||
use Lcobucci\JWT\Validation\Constraint;
|
||||
use Lcobucci\JWT\Validation\Constraint\SignedWith;
|
||||
use Lcobucci\JWT\Validation\Constraint\StrictValidAt;
|
||||
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||
use Psr\SimpleCache\InvalidArgumentException;
|
||||
|
||||
abstract class AbstractJwt implements JwtInterface
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
namespace App\Lib\Jwt;
|
||||
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Common\Interface\JwtInterface;
|
||||
|
||||
final class Jwt extends AbstractJwt implements JwtInterface {}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace App\Lib\Jwt;
|
||||
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Contract\ConfigInterface;
|
||||
use function Hyperf\Support\make;
|
||||
|
||||
@@ -2,11 +2,13 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware\Token;
|
||||
namespace App\Middleware\Admin;
|
||||
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use App\Constants\ResultCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Middleware\Token\AbstractTokenMiddleware;
|
||||
use Hyperf\Context\Context;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use function Hyperf\Support\env;
|
||||
@@ -28,4 +30,13 @@ final class AdminTokenMiddleware extends AbstractTokenMiddleware
|
||||
|
||||
if ($audience !== env('APP_NAME') .'_admin') throw new ErrException('token错误',ResultCode::JWT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UnencryptedToken $token
|
||||
* @return void
|
||||
*/
|
||||
public function setContext(UnencryptedToken $token): void
|
||||
{
|
||||
Context::set('current_admin_id',(int)$token->claims()?->get(RegisteredClaims::ID) ?? 0);
|
||||
}
|
||||
}
|
||||
108
app/Middleware/Admin/PermissionMiddleware.php
Normal file
108
app/Middleware/Admin/PermissionMiddleware.php
Normal file
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware\Admin;
|
||||
|
||||
use App\Annotation\Permission;
|
||||
use App\Common\Trait\AdminUserTrait;
|
||||
use App\Common\Trait\ParserRouterTrait;
|
||||
use App\Constants\AdminCode;
|
||||
use App\Constants\Model\AdminUser\AdminUserStatusCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Lib\Jwt\RequestScopedTokenTrait;
|
||||
use App\Model\AdminUser;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Di\Annotation\AnnotationCollector;
|
||||
use Hyperf\HttpServer\Router\Dispatched;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class PermissionMiddleware implements MiddlewareInterface
|
||||
{
|
||||
use RequestScopedTokenTrait;
|
||||
use AdminUserTrait;
|
||||
use ParserRouterTrait;
|
||||
|
||||
/**
|
||||
* @var AdminUser
|
||||
*/
|
||||
protected AdminUser $adminUserInfo;
|
||||
|
||||
/**
|
||||
* @param ContainerInterface $container
|
||||
*/
|
||||
public function __construct(protected ContainerInterface $container) {}
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$adminId = (int) $this->getToken()?->claims()?->get(RegisteredClaims::ID) ?? 0;
|
||||
if ($adminId <= 0) throw new ErrException('账户不存在');
|
||||
|
||||
$this->adminUserInfo = $this->getAdminUserInfo($adminId);
|
||||
if ($this->adminUserInfo->status == AdminUserStatusCode::DISABLE) throw new ErrException('账号已禁用',AdminCode::DISABLED);
|
||||
|
||||
// 超级管理员提前下场 不用判断权限
|
||||
if ($this->adminUserInfo->isSuperAdmin()) return $handler->handle($request);
|
||||
|
||||
$this->check($request->getAttribute(Dispatched::class));
|
||||
|
||||
return $handler->handle($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Dispatched $dispatched
|
||||
* @return bool
|
||||
*/
|
||||
private function check(Dispatched $dispatched): bool
|
||||
{
|
||||
$parseResult = $this->parse($dispatched->handler->callback);
|
||||
if (! $parseResult) return true;
|
||||
|
||||
[$controller, $method] = $parseResult;
|
||||
$annotations = AnnotationCollector::getClassMethodAnnotation($controller, $method);
|
||||
$classAnnotation = AnnotationCollector::getClassAnnotation($controller, Permission::class);
|
||||
/**
|
||||
* @var Permission[] $permissions
|
||||
*/
|
||||
$permissions = [];
|
||||
$classAnnotation && $permissions[] = $classAnnotation;
|
||||
$methodPermission = Arr::get($annotations, Permission::class);
|
||||
$methodPermission && $permissions[] = $methodPermission;
|
||||
|
||||
foreach ($permissions as $permission) {
|
||||
$this->handlePermission($permission);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Permission $permission
|
||||
* @return void
|
||||
*/
|
||||
private function handlePermission(Permission $permission): void
|
||||
{
|
||||
$operation = $permission->getOperation();
|
||||
$codes = $permission->getCode();
|
||||
|
||||
foreach ($codes as $code) {
|
||||
$isMenu = $this->adminUserInfo->hasPermission($code);
|
||||
|
||||
if ($operation === Permission::OPERATION_AND && !$isMenu) throw new ErrException('暂无权限',AdminCode::FORBIDDEN);
|
||||
|
||||
if ($operation === Permission::OPERATION_OR && $isMenu) return;
|
||||
}
|
||||
|
||||
if ($operation === Permission::OPERATION_OR) throw new ErrException('暂无权限',AdminCode::FORBIDDEN);
|
||||
}
|
||||
}
|
||||
@@ -2,11 +2,12 @@
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware\Token;
|
||||
namespace App\Middleware\Admin;
|
||||
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use App\Constants\ResultCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Middleware\Token\AbstractTokenMiddleware;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
|
||||
@@ -67,4 +68,13 @@ class RefreshAdminTokenMiddleware extends AbstractTokenMiddleware
|
||||
|
||||
if ($audience !== env('APP_NAME') .'_admin') throw new ErrException('token错误',ResultCode::JWT_ERROR);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UnencryptedToken $token
|
||||
* @return void
|
||||
*/
|
||||
public function setContext(UnencryptedToken $token): void
|
||||
{
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,10 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware\Token;
|
||||
|
||||
use App\Common\Interface\CheckTokenInterface;
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use App\Constants\ResultCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\CheckTokenInterface;
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Lib\Jwt\JwtFactory;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Stringable\Str;
|
||||
@@ -35,6 +35,8 @@ abstract class AbstractTokenMiddleware
|
||||
$this->checkToken->checkJwt($token);
|
||||
$this->checkIssuer($token);
|
||||
|
||||
$this->setContext($token);
|
||||
|
||||
return $handler->handle(
|
||||
value(
|
||||
static function (ServerRequestPlusInterface $request, UnencryptedToken $token) {
|
||||
@@ -54,6 +56,12 @@ abstract class AbstractTokenMiddleware
|
||||
|
||||
abstract public function getJwt(): JwtInterface;
|
||||
|
||||
/**
|
||||
* @param UnencryptedToken $token
|
||||
* @return void
|
||||
*/
|
||||
abstract public function setContext(UnencryptedToken $token): void;
|
||||
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @return Token
|
||||
|
||||
@@ -85,8 +85,8 @@ class AdminMenu extends Model
|
||||
return $this->belongsToMany(
|
||||
AdminRole::class,
|
||||
'admin_role_belongs_menu',
|
||||
'menu_id',
|
||||
'role_id'
|
||||
'admin_menu_id',
|
||||
'admin_role_id'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -65,9 +65,9 @@ class AdminRole extends Model
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
AdminMenu::class,
|
||||
'role_belongs_menu',
|
||||
'role_id',
|
||||
'menu_id'
|
||||
'admin_role_belongs_menu',
|
||||
'admin_role_id',
|
||||
'admin_menu_id'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -79,8 +79,8 @@ class AdminRole extends Model
|
||||
return $this->belongsToMany(
|
||||
AdminUser::class,
|
||||
'admin_user_belongs_role',
|
||||
'role_id',
|
||||
'user_id'
|
||||
'admin_role_id',
|
||||
'admin_user_id'
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,6 +6,9 @@ namespace App\Model;
|
||||
|
||||
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Hyperf\Database\Model\Events\Creating;
|
||||
|
||||
/**
|
||||
* @property int $id
|
||||
* @property int $admin_user_id
|
||||
@@ -20,6 +23,9 @@ namespace App\Model;
|
||||
*/
|
||||
class AdminUserLoginLog extends Model
|
||||
{
|
||||
|
||||
public bool $timestamps = false;
|
||||
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
@@ -28,10 +34,21 @@ class AdminUserLoginLog extends Model
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected array $fillable = [];
|
||||
protected array $fillable = ['id','admin_user_id', 'username', 'ip', 'os', 'browser', 'status', 'message', 'login_time', 'remark'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*/
|
||||
protected array $casts = ['id' => 'integer', 'admin_user_id' => 'integer', 'status' => 'integer'];
|
||||
|
||||
/**
|
||||
* @param Creating $event
|
||||
* @return void
|
||||
*/
|
||||
public function creating(Creating $event): void
|
||||
{
|
||||
if ($event->getModel()->login_time === null) {
|
||||
$event->getModel()->login_time = Carbon::now();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ class AdminUserOperationLog extends Model
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
protected array $fillable = [];
|
||||
protected array $fillable = ['id', 'admin_user_id','username', 'method', 'router', 'service_name', 'ip', 'ip_location', 'created_at', 'updated_at', 'remark'];
|
||||
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
|
||||
@@ -1,18 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Model\AdminRole;
|
||||
|
||||
final class AdminRoleRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(protected readonly AdminRole $model) {}
|
||||
}
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Model\AdminUser;
|
||||
use Hyperf\Database\Concerns\BuildsQueries;
|
||||
use Hyperf\Database\Model\Builder;
|
||||
use Hyperf\Database\Model\Model;
|
||||
|
||||
/**
|
||||
* Class AdminUserRepository
|
||||
* @extends BaseRepository<AdminUser>
|
||||
*/
|
||||
final class AdminUserRepository extends BaseRepository
|
||||
{
|
||||
public function __construct(protected readonly AdminUser $model) {}
|
||||
|
||||
/**
|
||||
* @param string $username
|
||||
* @return AdminUser|null
|
||||
*/
|
||||
public function findByUserName(string $username): AdminUser|null
|
||||
{
|
||||
// @phpstan-ignore-next-line
|
||||
return $this->model->newQuery()
|
||||
->where('username', $username)
|
||||
->first();
|
||||
}
|
||||
}
|
||||
114
app/Request/Admin/AdminMenuRequest.php
Normal file
114
app/Request/Admin/AdminMenuRequest.php
Normal file
@@ -0,0 +1,114 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Request\Admin;
|
||||
|
||||
use Hyperf\Validation\Request\FormRequest;
|
||||
|
||||
class AdminMenuRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'parent_id' => 'sometimes|integer',
|
||||
'name' => 'required|string|max:255',
|
||||
'path' => 'sometimes|string|max:255',
|
||||
'component' => 'sometimes|string|max:255',
|
||||
'redirect' => 'sometimes|string|max:255',
|
||||
'status' => 'sometimes|integer',
|
||||
'sort' => 'sometimes|integer',
|
||||
'remark' => 'sometimes|string|max:255',
|
||||
'meta.title' => 'required|string|max:255',
|
||||
'meta.i18n' => 'sometimes|string|max:255',
|
||||
'meta.badge' => 'sometimes|string|max:255',
|
||||
'meta.link' => 'sometimes|string|max:255',
|
||||
'meta.icon' => 'sometimes|string|max:255',
|
||||
'meta.affix' => 'sometimes|boolean',
|
||||
'meta.hidden' => 'sometimes|boolean',
|
||||
'meta.type' => 'sometimes|string|max:255',
|
||||
'meta.cache' => 'sometimes|boolean',
|
||||
'meta.breadcrumbEnable' => 'sometimes|boolean',
|
||||
'meta.copyright' => 'sometimes|boolean',
|
||||
'meta.componentPath' => 'sometimes|string|max:64',
|
||||
'meta.componentSuffix' => 'sometimes|string|max:4',
|
||||
'meta.activeName' => 'sometimes|string|max:255',
|
||||
'btnPermission' => 'sometimes|array',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return parent::messages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array|array[]
|
||||
*/
|
||||
protected array $scenes = [
|
||||
'update' => [
|
||||
'parent_id',
|
||||
'name',
|
||||
'path',
|
||||
'component',
|
||||
'redirect',
|
||||
'status',
|
||||
'sort',
|
||||
'remark',
|
||||
'meta.title',
|
||||
'meta.i18n',
|
||||
'meta.badge',
|
||||
'meta.link',
|
||||
'meta.icon',
|
||||
'meta.affix',
|
||||
'meta.hidden',
|
||||
'meta.type',
|
||||
'meta.cache',
|
||||
'meta.breadcrumbEnable',
|
||||
'meta.copyright',
|
||||
'meta.componentPath',
|
||||
'meta.componentSuffix',
|
||||
'meta.activeName',
|
||||
'btnPermission',
|
||||
],
|
||||
'create' => [
|
||||
'parent_id',
|
||||
'name',
|
||||
'path',
|
||||
'component',
|
||||
'redirect',
|
||||
'status',
|
||||
'sort',
|
||||
'remark',
|
||||
'meta.title',
|
||||
'meta.i18n',
|
||||
'meta.badge',
|
||||
'meta.link',
|
||||
'meta.icon',
|
||||
'meta.affix',
|
||||
'meta.hidden',
|
||||
'meta.type',
|
||||
'meta.cache',
|
||||
'meta.breadcrumbEnable',
|
||||
'meta.copyright',
|
||||
'meta.componentPath',
|
||||
'meta.componentSuffix',
|
||||
'meta.activeName',
|
||||
'btnPermission',
|
||||
],
|
||||
];
|
||||
}
|
||||
79
app/Request/Admin/AdminRoleRequest.php
Normal file
79
app/Request/Admin/AdminRoleRequest.php
Normal file
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Request\Admin;
|
||||
|
||||
use App\Common\Trait\HttpMethodTrait;
|
||||
use Hyperf\Validation\Request\FormRequest;
|
||||
|
||||
class AdminRoleRequest extends FormRequest
|
||||
{
|
||||
use HttpMethodTrait;
|
||||
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
$rules = [
|
||||
'name' => 'required|string|max:60',
|
||||
'code' => [
|
||||
'required',
|
||||
'string',
|
||||
'max:60',
|
||||
'regex:/^[a-zA-Z0-9_]+$/',
|
||||
],
|
||||
'status' => 'sometimes|integer|in:1,2',
|
||||
'sort' => 'required|integer',
|
||||
'remark' => 'nullable|string|max:255',
|
||||
'permissions' => 'sometimes|array',
|
||||
'permissions.*' => 'string|exists:admin_menu,name',
|
||||
];
|
||||
if ($this->isCreate()) {
|
||||
$rules['code'][] = 'unique:admin_role,code';
|
||||
}
|
||||
if ($this->isUpdate()) {
|
||||
$rules['code'][] = 'unique:admin_role,code,' . $this->route('id');
|
||||
}
|
||||
|
||||
return $rules;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return parent::messages();
|
||||
}
|
||||
|
||||
protected array $scenes = [
|
||||
'update' => [
|
||||
'code',
|
||||
'name',
|
||||
'status',
|
||||
'sort',
|
||||
'remark',
|
||||
],
|
||||
'create' => [
|
||||
'code',
|
||||
'name',
|
||||
'status',
|
||||
'sort',
|
||||
'remark',
|
||||
],
|
||||
'batch_grant_permission' => [
|
||||
'permissions',
|
||||
'permissions.*',
|
||||
]
|
||||
];
|
||||
}
|
||||
81
app/Request/Admin/AdminUserRequest.php
Normal file
81
app/Request/Admin/AdminUserRequest.php
Normal file
@@ -0,0 +1,81 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Request\Admin;
|
||||
|
||||
use Hyperf\Validation\Request\FormRequest;
|
||||
|
||||
class AdminUserRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'username' => 'required|string|max:20',
|
||||
'user_type' => 'required|integer',
|
||||
'nickname' => ['required', 'string', 'max:60', 'regex:/^[^\s]+$/'],
|
||||
'phone' => 'sometimes|string|max:12',
|
||||
'email' => 'sometimes|string|max:60|email:rfc,dns',
|
||||
'avatar' => 'sometimes|string|max:255|url',
|
||||
'signed' => 'sometimes|string|max:255',
|
||||
'status' => 'sometimes|integer',
|
||||
'backend_setting' => 'sometimes|array|max:255',
|
||||
'remark' => 'sometimes|string|max:255',
|
||||
'password' => 'sometimes|string|min:6|max:20',
|
||||
'role_codes' => 'required|array',
|
||||
'role_codes.*' => 'string|exists:admin_role,code',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return parent::messages();
|
||||
}
|
||||
|
||||
protected array $scenes = [
|
||||
'update' => [
|
||||
'username',
|
||||
'user_type',
|
||||
'nickname',
|
||||
'phone',
|
||||
'email',
|
||||
'avatar',
|
||||
'signed',
|
||||
'status',
|
||||
'backend_setting',
|
||||
'remark',
|
||||
'password',
|
||||
],
|
||||
'create' => [
|
||||
'username',
|
||||
'user_type',
|
||||
'nickname',
|
||||
'phone',
|
||||
'email',
|
||||
'avatar',
|
||||
'signed',
|
||||
'status',
|
||||
'backend_setting',
|
||||
'remark',
|
||||
'password',
|
||||
],
|
||||
'batch_grant_role' => [
|
||||
'role_codes',
|
||||
'role_codes.*',
|
||||
]
|
||||
];
|
||||
}
|
||||
@@ -22,7 +22,20 @@ class LoginRequest extends FormRequest
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
|
||||
'username' => 'required|string|exists:admin_user,username',
|
||||
'password' => 'required|string'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return parent::messages();
|
||||
}
|
||||
|
||||
protected array $scenes = [
|
||||
'login' => ['username', 'password'],
|
||||
];
|
||||
}
|
||||
|
||||
57
app/Request/Admin/PermissionRequest.php
Normal file
57
app/Request/Admin/PermissionRequest.php
Normal file
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Request\Admin;
|
||||
|
||||
use Hyperf\Validation\Request\FormRequest;
|
||||
|
||||
class PermissionRequest extends FormRequest
|
||||
{
|
||||
/**
|
||||
* Determine if the user is authorized to make this request.
|
||||
*/
|
||||
public function authorize(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the validation rules that apply to the request.
|
||||
*/
|
||||
public function rules(): array
|
||||
{
|
||||
return [
|
||||
'nickname' => 'sometimes|string|max:255',
|
||||
'new_password' => 'sometimes|confirmed|string|min:8',
|
||||
'new_password_confirmation' => 'sometimes|string|min:8',
|
||||
'old_password' => ['sometimes', 'string'],
|
||||
'avatar' => 'sometimes|string|max:255',
|
||||
'signed' => 'sometimes|string|max:255',
|
||||
'backend_setting' => 'sometimes|array',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function messages(): array
|
||||
{
|
||||
return parent::messages();
|
||||
}
|
||||
|
||||
/**
|
||||
* @var array|array[]
|
||||
*/
|
||||
protected array $scenes = [
|
||||
'update' => [
|
||||
'nickname',
|
||||
'new_password',
|
||||
'new_password_confirmation',
|
||||
'old_password',
|
||||
'avatar',
|
||||
'signed',
|
||||
'backend_setting',
|
||||
],
|
||||
];
|
||||
}
|
||||
137
app/Service/Admin/AdminUser/MenuService.php
Normal file
137
app/Service/Admin/AdminUser/MenuService.php
Normal file
@@ -0,0 +1,137 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\AdminUser;
|
||||
|
||||
use App\Common\Repository\AdminMenuRepository;
|
||||
use App\Exception\ErrException;
|
||||
use App\Model\AdminMenu;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class MenuService extends BaseAdminService
|
||||
{
|
||||
/**
|
||||
* @var AdminMenuRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminMenuRepository $adminMenuRepository;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return $this->adminReturn->success('success',$this->adminMenuRepository->list([
|
||||
'children' => true,
|
||||
'parent_id' => 0
|
||||
])?->toArray() ?? []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function create(): array
|
||||
{
|
||||
$data = array_merge($this->getRequestData(),[
|
||||
'created_by' => $this->adminId
|
||||
]);
|
||||
if (empty($data['parent_id'])) $data['parent_id'] = 0;
|
||||
/**
|
||||
* @var AdminMenu $model
|
||||
*/
|
||||
$model = $this->adminMenuRepository->create($data);
|
||||
|
||||
if (!$model) throw new ErrException('添加失败');
|
||||
|
||||
if ($data['meta']['type'] !== 'M' || empty($data['btnPermission'])) return $this->adminReturn->success('success',$model->toArray());
|
||||
|
||||
foreach ($data['btnPermission'] as $item) {
|
||||
$this->adminMenuRepository->create([
|
||||
'parent_id' => $model->id,
|
||||
'name' => $item['code'],
|
||||
'sort' => 0,
|
||||
'status' => 1,
|
||||
'meta' => [
|
||||
'title' => $item['title'],
|
||||
'i18n' => $item['i18n'],
|
||||
'type' => 'B'
|
||||
],
|
||||
]);
|
||||
}
|
||||
|
||||
return $this->adminReturn->success('success',$model->toArray());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function update(int $id): array
|
||||
{
|
||||
$data = array_merge($this->getRequestData(),[
|
||||
'updated_by' => $this->adminId
|
||||
]);
|
||||
|
||||
$model = $this->adminMenuRepository->updateById($id, $data);
|
||||
|
||||
if (!$model) throw new ErrException('修改失败');
|
||||
|
||||
if ($data['meta']['type'] !== 'M' || !isset($data['btnPermission'])) return $this->adminReturn->success();
|
||||
|
||||
$existsBtnPermissions = array_flip(
|
||||
$this->adminMenuRepository
|
||||
->getQuery()
|
||||
->where('parent_id', $id)
|
||||
->whereJsonContains('meta->type', 'B')
|
||||
->pluck('id')
|
||||
->toArray()
|
||||
);
|
||||
|
||||
if (!empty($data['btnPermission'])) {
|
||||
foreach ($data['btnPermission'] as $item) {
|
||||
if (empty($item['type']) || $item['type'] !== 'B') continue;
|
||||
|
||||
$data = [
|
||||
'name' => $item['code'],
|
||||
'meta' => [
|
||||
'title' => $item['title'],
|
||||
'i18n' => $item['i18n'],
|
||||
'type' => 'B'
|
||||
],
|
||||
];
|
||||
|
||||
if (!empty($item['id'])) {
|
||||
$this->adminMenuRepository->updateById($item['id'], $data);
|
||||
unset($existsBtnPermissions[$item['id']]);
|
||||
} else {
|
||||
$data['parent_id'] = $id;
|
||||
$this->adminMenuRepository->create($data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($existsBtnPermissions)) $this->adminMenuRepository->deleteById(array_keys($existsBtnPermissions));
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function delete(): array
|
||||
{
|
||||
$res = $this->adminMenuRepository->deleteById($this->getRequestData());
|
||||
|
||||
if (!$res) throw new ErrException('删除失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
}
|
||||
135
app/Service/Admin/AdminUser/PermissionService.php
Normal file
135
app/Service/Admin/AdminUser/PermissionService.php
Normal file
@@ -0,0 +1,135 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\AdminUser;
|
||||
|
||||
use App\Common\Repository\AdminMenuRepository;
|
||||
use App\Common\Repository\AdminRoleRepository;
|
||||
use App\Common\Trait\AdminUserTrait;
|
||||
use App\Constants\Model\AdminUser\AdminMenuStatusCode;
|
||||
use App\Constants\Model\AdminUser\AdminRoleStatusCode;
|
||||
use App\Constants\ResultCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class PermissionService extends BaseAdminService
|
||||
{
|
||||
use AdminUserTrait;
|
||||
|
||||
/**
|
||||
* @var AdminRoleRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminRoleRepository $adminRoleRepository;
|
||||
|
||||
/**
|
||||
* @var AdminMenuRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminMenuRepository $adminMenuRepository;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->getAdminUserInfo($this->adminId)->isSuperAdmin() ?
|
||||
$this->getAdminMenuBySuperAdmin() :
|
||||
$this->getAdminMenuByAdminId()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getAdminMenuByAdminId(): array
|
||||
{
|
||||
$permissions = $this->getAdminUserInfo($this->adminId)->getPermissions()->pluck('name')->unique();
|
||||
|
||||
$menuList = $permissions->isEmpty() ?
|
||||
[] :
|
||||
$this->adminMenuRepository->list([
|
||||
'status' => AdminMenuStatusCode::Normal,
|
||||
'name' => $permissions->toArray()
|
||||
])->toArray();
|
||||
|
||||
$tree = [];
|
||||
$map = [];
|
||||
|
||||
foreach ($menuList as &$menu) {
|
||||
$menu['children'] = [];
|
||||
$map[$menu['id']] = &$menu;
|
||||
}
|
||||
unset($menu);
|
||||
|
||||
foreach ($menuList as &$menu) {
|
||||
$pid = $menu['parent_id'];
|
||||
if ($pid === 0 || !isset($map[$pid])) {
|
||||
$tree[] = &$menu;
|
||||
} else {
|
||||
$map[$pid]['children'][] = &$menu;
|
||||
}
|
||||
}
|
||||
unset($menu);
|
||||
|
||||
return $tree;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function getAdminMenuBySuperAdmin(): array
|
||||
{
|
||||
return $this->adminMenuRepository->list([
|
||||
'status' => AdminMenuStatusCode::Normal,
|
||||
'children' => true,
|
||||
'parent_id' => 0,
|
||||
])?->toArray() ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function getRoleByAdminUser(): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->getAdminUserInfo($this->adminId)->isSuperAdmin() ?
|
||||
$this->adminRoleRepository->list(['status' => AdminRoleStatusCode::Normal])->toArray() :
|
||||
$this->getAdminUserInfo($this->adminId)->getRoles(['name', 'code', 'remark'])->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function update(): array
|
||||
{
|
||||
$userInfo = $this->getAdminUserInfo($this->adminId);
|
||||
if (!$userInfo) throw new ErrException('用户不存在');
|
||||
|
||||
$data = $this->getRequestData();
|
||||
|
||||
if (Arr::exists($data, 'new_password')) {
|
||||
if (!$userInfo->verifyPassword(Arr::get($data,'old_password')))
|
||||
throw new ErrException('旧密码错误',ResultCode::OLD_PASSWORD_ERROR);
|
||||
|
||||
$data['password'] = $data['new_password'];
|
||||
}
|
||||
|
||||
if (!$this->adminUserRepository->updateById($userInfo->id, $data)) throw new ErrException('更新失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
}
|
||||
139
app/Service/Admin/AdminUser/RoleService.php
Normal file
139
app/Service/Admin/AdminUser/RoleService.php
Normal file
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\AdminUser;
|
||||
|
||||
use App\Common\Repository\AdminMenuRepository;
|
||||
use App\Common\Repository\AdminRoleRepository;
|
||||
use App\Exception\ErrException;
|
||||
use App\Model\AdminMenu;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class RoleService extends BaseAdminService
|
||||
{
|
||||
/**
|
||||
* @var AdminRoleRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminRoleRepository $adminRoleRepository;
|
||||
|
||||
/**
|
||||
* @var AdminMenuRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminMenuRepository $adminMenuRepository;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->adminRoleRepository->page(
|
||||
$this->getRequestData(),
|
||||
$this->getCurrentPage(),
|
||||
$this->getPageSize()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function create(): array
|
||||
{
|
||||
if (!$this->adminRoleRepository->create(
|
||||
array_merge(
|
||||
$this->getRequestData(),
|
||||
['created_by' => $this->adminId]
|
||||
)
|
||||
)) throw new ErrException('添加失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function update(int $id): array
|
||||
{
|
||||
if (!$this->adminRoleRepository->updateById(
|
||||
$id,
|
||||
array_merge(
|
||||
$this->getRequestData(),
|
||||
['updated_by' => $this->adminId]
|
||||
)
|
||||
)) throw new ErrException('更新失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function delete(): array
|
||||
{
|
||||
if (!$this->adminRoleRepository->deleteById($this->getRequestData())) throw new ErrException('删除失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function getRole(int $id): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->adminRoleRepository
|
||||
->findById($id)
|
||||
->adminMenus()
|
||||
->get()
|
||||
->map(static fn (AdminMenu $adminMenu) => $adminMenu->only([
|
||||
'id' , 'name'
|
||||
]))->toArray()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $id
|
||||
* @return array
|
||||
*/
|
||||
public function setRole(int $id): array
|
||||
{
|
||||
if (!$this->adminRoleRepository->existsById($id)) throw new ErrException('角色不存在');
|
||||
|
||||
$permissionsCode = Arr::get($this->getRequestData(), 'permissions', []);
|
||||
|
||||
if (count($permissionsCode) === 0) {
|
||||
$this->adminRoleRepository->findById($id)->adminMenus()->detach();
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
|
||||
if (!$this->adminRoleRepository
|
||||
->findById($id)
|
||||
->adminMenus()
|
||||
->sync(
|
||||
$this->adminMenuRepository
|
||||
->list([
|
||||
'code' => $permissionsCode
|
||||
])
|
||||
->map(static fn ($item) => $item->id)
|
||||
->toArray()
|
||||
)) throw new ErrException('更新失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
}
|
||||
@@ -12,17 +12,15 @@ namespace App\Service\Admin\AdminUser;
|
||||
|
||||
use App\Cache\Redis\Lua\RateLimit;
|
||||
use App\Cache\Redis\RedisCache;
|
||||
use App\Common\Repository\AdminRoleRepository;
|
||||
use App\Common\Repository\AdminUserRepository;
|
||||
use App\Common\Trait\AdminUserTrait;
|
||||
use App\Exception\ErrException;
|
||||
use App\Lib\Jwt\RequestScopedTokenTrait;
|
||||
use App\Model\AdminRole;
|
||||
use App\Repository\AdminRoleRepository;
|
||||
use App\Repository\AdminUserRepository;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use App\Service\BaseTokenService;
|
||||
use App\Trait\AdminUserTrait;
|
||||
use Hyperf\Collection\Arr;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
|
||||
class UserService extends BaseAdminService
|
||||
{
|
||||
@@ -46,21 +44,15 @@ class UserService extends BaseAdminService
|
||||
#[Inject]
|
||||
protected AdminRoleRepository $adminRoleRepository;
|
||||
|
||||
#[Inject]
|
||||
protected RedisCache $redisCache;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
$this->redisCache->with()->set('123',1);
|
||||
$this->redisCache->with()->lua(RateLimit::class)->check('user:123', 10, 60);
|
||||
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
Arr::only(
|
||||
$this->getAdminUserInfo($this->adminId) ?: [],
|
||||
$this->getAdminUserInfo($this->adminId)?->toArray() ?: [],
|
||||
['username', 'nickname', 'avatar', 'signed', 'backend_setting', 'phone', 'email']
|
||||
)
|
||||
);
|
||||
@@ -190,7 +182,7 @@ class UserService extends BaseAdminService
|
||||
'code' => $this->request->input('role_codes')
|
||||
])->map(static function(AdminRole $adminRole) {
|
||||
return $adminRole->id;
|
||||
})->all()
|
||||
})
|
||||
);
|
||||
|
||||
return $this->adminReturn->success();
|
||||
|
||||
@@ -10,11 +10,12 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin;
|
||||
|
||||
use App\Exception\ErrException;
|
||||
use App\Lib\Jwt\RequestScopedTokenTrait;
|
||||
use App\Lib\Return\AdminReturn;
|
||||
use Hyperf\Context\Context;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
|
||||
abstract class BaseAdminService
|
||||
{
|
||||
@@ -35,19 +36,27 @@ abstract class BaseAdminService
|
||||
protected AdminReturn $adminReturn;
|
||||
|
||||
/**
|
||||
* 管理员 id
|
||||
* @var int
|
||||
* @param string $name
|
||||
* @return \current_admin_id|mixed
|
||||
*/
|
||||
protected int $adminId = 0;
|
||||
|
||||
/**
|
||||
* 主构造函数
|
||||
*/
|
||||
public function __construct()
|
||||
public function __get(string $name)
|
||||
{
|
||||
$this->adminId = (int) $this->getToken()?->claims()?->get(RegisteredClaims::ID) ?? 0;
|
||||
if ($name === 'adminId') return Context::get('current_admin_id',0);
|
||||
|
||||
if (!property_exists($this, $name)) throw new ErrException('属性未定义');
|
||||
|
||||
return $this->$name;
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 主构造函数
|
||||
// */
|
||||
// public function __construct()
|
||||
// {
|
||||
// $this->adminId = Context::get('current_admin_id',0);
|
||||
// var_dump('BaseAdminService获取到的'.$this->adminId);
|
||||
// }
|
||||
|
||||
/**
|
||||
* 主函数抽象类
|
||||
*/
|
||||
|
||||
51
app/Service/Admin/Log/AdminUserLoginLogService.php
Normal file
51
app/Service/Admin/Log/AdminUserLoginLogService.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Log;
|
||||
|
||||
use App\Common\Repository\AdminUserLoginLogRepository;
|
||||
use App\Exception\ErrException;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class AdminUserLoginLogService extends BaseAdminService
|
||||
{
|
||||
/**
|
||||
* @var AdminUserLoginLogRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminUserLoginLogRepository $adminUserLoginLogRepository;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->adminUserLoginLogRepository->page(
|
||||
$this->getRequestData(),
|
||||
$this->getCurrentPage(),
|
||||
$this->getPageSize()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function deleteLog(): array
|
||||
{
|
||||
if (!$this->adminUserLoginLogRepository->deleteById($this->request->input('ids')))
|
||||
throw new ErrException('删除失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
}
|
||||
51
app/Service/Admin/Log/AdminUserOperationLogService.php
Normal file
51
app/Service/Admin/Log/AdminUserOperationLogService.php
Normal file
@@ -0,0 +1,51 @@
|
||||
<?php
|
||||
/**
|
||||
* This service file is part of item.
|
||||
*
|
||||
* @author ctexthuang
|
||||
* @contact ctexthuang@qq.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Log;
|
||||
|
||||
use App\Common\Repository\AdminUserOperationLogRepository;
|
||||
use App\Exception\ErrException;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
|
||||
class AdminUserOperationLogService extends BaseAdminService
|
||||
{
|
||||
/**
|
||||
* @var AdminUserOperationLogRepository
|
||||
*/
|
||||
#[Inject]
|
||||
protected AdminUserOperationLogRepository $adminUserOperationLogRepository;
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function handle(): array
|
||||
{
|
||||
return $this->adminReturn->success(
|
||||
'success',
|
||||
$this->adminUserOperationLogRepository->page(
|
||||
$this->getRequestData(),
|
||||
$this->getCurrentPage(),
|
||||
$this->getPageSize()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
public function deleteLog(): array
|
||||
{
|
||||
if (!$this->adminUserOperationLogRepository->deleteById($this->request->input('ids')))
|
||||
throw new ErrException('删除失败');
|
||||
|
||||
return $this->adminReturn->success();
|
||||
}
|
||||
}
|
||||
@@ -10,11 +10,9 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service\Admin\Login;
|
||||
|
||||
use App\Common\Repository\AdminUserRepository;
|
||||
use App\Constants\Model\AdminUser\AdminUserStatusCode;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\JwtInterface;
|
||||
use App\Lib\Jwt\JwtFactory;
|
||||
use App\Repository\AdminUserRepository;
|
||||
use App\Service\Admin\BaseAdminService;
|
||||
use App\Service\BaseTokenService;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
@@ -48,7 +46,6 @@ class LoginService extends BaseAdminService
|
||||
}
|
||||
|
||||
if ($adminInfo->status == AdminUserStatusCode::DISABLE) throw new ErrException('用户已禁用');
|
||||
|
||||
$jwtHandle = $this->tokenService->setJwt('admin')->getJwt();
|
||||
|
||||
return $this->adminReturn->success('success',[
|
||||
|
||||
@@ -10,13 +10,13 @@ declare(strict_types=1);
|
||||
|
||||
namespace App\Service;
|
||||
|
||||
use App\Common\Interface\CheckTokenInterface;
|
||||
use App\Common\Interface\JwtInterface;
|
||||
use App\Exception\ErrException;
|
||||
use App\Interface\CheckTokenInterface;
|
||||
use App\Lib\Jwt\JwtFactory;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Lcobucci\JWT\Token\RegisteredClaims;
|
||||
use Lcobucci\JWT\UnencryptedToken;
|
||||
use App\Interface\JwtInterface;
|
||||
use function Hyperf\Support\value;
|
||||
|
||||
final class BaseTokenService implements CheckTokenInterface
|
||||
@@ -55,20 +55,4 @@ final class BaseTokenService implements CheckTokenInterface
|
||||
$this->jwt = $jwt;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param UnencryptedToken $token
|
||||
* @return \Closure
|
||||
*/
|
||||
public function refreshToken(UnencryptedToken $token): \Closure
|
||||
{
|
||||
return value(static function (JwtInterface $jwt) use ($token) {
|
||||
$jwt->addBlackList($token);
|
||||
return [
|
||||
'access_token' => $jwt->builderAccessToken($token->claims()->get(RegisteredClaims::ID))->toString(),
|
||||
'refresh_token' => $jwt->builderRefreshToken($token->claims()->get(RegisteredClaims::ID))->toString(),
|
||||
'expire_at' => (int) $jwt->getConfig('ttl', 0),
|
||||
];
|
||||
}, $this->getJwt());
|
||||
}
|
||||
}
|
||||
@@ -11,5 +11,5 @@ declare(strict_types=1);
|
||||
*/
|
||||
return [
|
||||
Hyperf\Database\Schema\Blueprint::class => App\Common\Macros\BlueprintMacros::class,
|
||||
App\Interface\CheckTokenInterface::class => App\Service\BaseTokenService::class,
|
||||
App\Common\Interface\CheckTokenInterface::class => App\Service\BaseTokenService::class,
|
||||
];
|
||||
|
||||
Reference in New Issue
Block a user