获取菜单
This commit is contained in:
parent
087207364f
commit
7c57ed4b43
|
|
@ -14,4 +14,7 @@ DB_PREFIX=
|
|||
REDIS_HOST=localhost
|
||||
REDIS_AUTH=(null)
|
||||
REDIS_PORT=6379
|
||||
REDIS_DB=0
|
||||
REDIS_DB=0
|
||||
|
||||
JWT_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC13F3kPpJqEMTHEQ+wS8eRPlFKGRrLbEBh2o0a5Ccsdx/zImo+TDKXLPyasZSquFqEL+tuTNST+WJPSiYySYpaSb5w1LJXGq/hi9DnjjosBuqxtpmrG1uwlu1wvi1RmiynCfBnKfBCc0g7yGZ4XcQ665ftbNrHBLtSB/xpyf1N7PwYKKOG2KmrJKv1DlIt30XsdXwReiGl80NHm4AQvuGAlZ7W0aL3V5JxK30gQxLYJYRnMKLpaKV/JDxxIWOUEv0wL8sCeWbjxv4xLYoEhUO0DY+h0ZZAxafxTNeuhvoO7aCOUEhZSvke7n+THUiFVhkJy0ccEr59Kp+1N0kyxFBHAgMBAAECggEAICt4LGzpJ3wJ4xDgjpYJGmdEp+/i7oMarHSlq1EaoOH9s9utoZGHDXj2wkKRgtWTpXh4lA1hOT/PJSl/sjuSDsCmwHzPg1sEK8i4zo05OxqKH5+mdT8krAs2u0/Y4mt8ZJv8e7NOfeK4r2KWxcoIcUfFm0k7NiNfI3aoLup9NXBeWqBnHl5kgtsEDeU1KoEX8U/HW8oTyQqGAW20Jz9mXN1XneADjGpSUwQY0oaG620S51WBKIicKO7R3NP7J67IyCVTnKyAMuTEBoEcweG/WGpGdI+3AkUcJFMrMkwYX/X4Df5zEF93mXf6DxvEI2m1jdOrVZ42yJEg0pE5H1sGuQKBgQD4d1ELhSM8fub31jJrXNewHEIwszFcTiUbEjFiO0Cep5lYuGVZuWdMye2Gc+ZphrtEalLNGFt+sw9MuoqxIYhipnUz9ksHKDRoxR4dOebXCPgP/LHW4P8KAPcvMUr4xNS5hrh9qajjTaRepZwjcIS9CWr8QHDHF6a74K+XGxUn8wKBgQC7YAk34zOmx7BQC6nn7U+yM8Dksfdt2a+/rBGvqp6ILh6DTdeCI3b61L6NZKzVFg7YFOIQbBL88HOm3xz1MAJB4Q/a6A1Rz+lCKnkJ7d+En733nyh1HJlRK9FDaIPHm/iHi/FsJ9wHnrsAa7Vofp4QHWjQB6cUo2nvRoo4S8A/XQKBgEiuhourJ5KTwLaw9tDHOOTwb0BVutO4nEwd90o38QA4ILh+QE+N17TzwMK69qTZ37/0pkIOpP0cHhag3t9P4tiQvuozWuE+Fo6rUtLT1D4FBqOOlOs5qAFiJOyuK7M3yM54pVFFJv1PAg0ZvuHzETFHJv+hThw/Q+vjnxnBt1+XAoGBAJazqPZgMBzFotLebqrwvRaQdWX6lQyu9qFsXVUyHwtcPIJSyzAKIhmfnhrOjAteEFZOhXu70JHLOtlNvVaeZFJkF4Jy/LN+SxdCXdNUlF9wszNDuSBn/g/A9DAJEWQr1/n83hGlBVzDl5fBCUif/bTsUm5umT0KKZue2nBozJipAoGAX/xrRKIY8yfab7/Dc2THtrQA1fmOxDSK5Vki65N4tprsA4UiTdOegFgFGJfTnr8AkUG0leQ0mkYCNoXL1J0MnN92ULdfyAEn9bKW6dl7yVUOsyGLKMqasifI99rZS3aApMtF3/ekoymn+hbV3ftmtDi3HYzJ5QtBXPWXCvsN8LY="
|
||||
JWT_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtdxd5D6SahDExxEPsEvHkT5RShkay2xAYdqNGuQnLHcf8yJqPkwylyz8mrGUqrhahC/rbkzUk/liT0omMkmKWkm+cNSyVxqv4YvQ5446LAbqsbaZqxtbsJbtcL4tUZospwnwZynwQnNIO8hmeF3EOuuX7WzaxwS7Ugf8acn9Tez8GCijhtipqySr9Q5SLd9F7HV8EXohpfNDR5uAEL7hgJWe1tGi91eScSt9IEMS2CWEZzCi6WilfyQ8cSFjlBL9MC/LAnlm48b+MS2KBIVDtA2PodGWQMWn8UzXrob6Du2gjlBIWUr5Hu5/kx1IhVYZCctHHBK+fSqftTdJMsRQRwIDAQAB"
|
||||
|
|
|
|||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Annotation;
|
||||
|
||||
use Attribute;
|
||||
use Hyperf\Di\Annotation\AbstractAnnotation;
|
||||
|
||||
/**
|
||||
* 管理端/机构端/商户端
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class Auth extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* construct.
|
||||
*/
|
||||
public function __construct(public bool $needLogin=true, public bool $needAuth=true, public bool $needLog = true, public string $auth="*")
|
||||
{}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
<?php
|
||||
|
||||
namespace App\Annotation;
|
||||
|
||||
use Attribute;
|
||||
use Hyperf\Di\Annotation\AbstractAnnotation;
|
||||
|
||||
/**
|
||||
* 用户端
|
||||
*/
|
||||
#[Attribute(Attribute::TARGET_METHOD)]
|
||||
class User extends AbstractAnnotation
|
||||
{
|
||||
/**
|
||||
* construct.
|
||||
*/
|
||||
public function __construct(public bool $needLogin=true)
|
||||
{}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Aspect;
|
||||
|
||||
use App\Annotation\Auth;
|
||||
use App\Model\AccountLog;
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\Di\Annotation\Aspect;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\Di\Aop\AbstractAspect;
|
||||
use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
use Hyperf\Di\Exception\AnnotationException;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
||||
#[Aspect]
|
||||
class AuthAspect extends AbstractAspect
|
||||
{
|
||||
#[Inject]
|
||||
protected RequestInterface $request;
|
||||
#[Inject]
|
||||
protected ResponseInterface $response;
|
||||
|
||||
public array $annotations = [
|
||||
Auth::class
|
||||
];
|
||||
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param ProceedingJoinPoint $proceedingJoinPoint
|
||||
* @return mixed|\Psr\Http\Message\ResponseInterface
|
||||
* @throws AnnotationException|\Hyperf\Di\Exception\Exception
|
||||
*/
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint)
|
||||
{
|
||||
// 切面切入后,执行对应的方法会由此来负责
|
||||
$authorization = $this->getAuthorizationAnnotation($proceedingJoinPoint);
|
||||
$isLogin = $this->request->getAttribute("isLogin",false);
|
||||
if ($authorization->needLogin && !$isLogin) {
|
||||
return $this->response->json(['code' => 3,'msg' => '登录已过期']);
|
||||
}
|
||||
$admin = $this->request->getAttribute("account");
|
||||
if ($authorization->needLogin && $authorization->needAuth) {
|
||||
if (!$isLogin || empty($admin) || !$this->checkPermission($authorization->auth, $this->request->getMethod(), $admin)) {
|
||||
return $this->response->json(['code' => 2,'msg' => '权限不足']);
|
||||
}
|
||||
}
|
||||
$response = $proceedingJoinPoint->process();
|
||||
// 记录日志
|
||||
if ($isLogin && !empty($admin) && $authorization->needLog && $authorization->auth != "*") {
|
||||
AccountLog::recordLog($this->request, $admin, $authorization->auth, $response);
|
||||
}
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* desc: 获取注解类
|
||||
* @param ProceedingJoinPoint $proceedingJoinPoint
|
||||
* @return Auth
|
||||
* @throws AnnotationException
|
||||
*/
|
||||
protected function getAuthorizationAnnotation(ProceedingJoinPoint $proceedingJoinPoint): Auth {
|
||||
$annotation = $proceedingJoinPoint->getAnnotationMetadata()->method[Auth::class] ?? null;
|
||||
if (!$annotation instanceof Auth) {
|
||||
throw new AnnotationException("Annotation Auth couldn't be collected successfully.");
|
||||
}
|
||||
return $annotation;
|
||||
}
|
||||
|
||||
/**
|
||||
* desc: 校验操作权限
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param string $auth
|
||||
* @param string $method
|
||||
* @param array $account
|
||||
* @return bool
|
||||
*/
|
||||
protected function checkPermission(string $auth, string $method, array $account): bool {
|
||||
if ($auth == "*" || $account['master_flag']) return true;
|
||||
$container = ApplicationContext::getContainer();
|
||||
$redis = $container->get(\Hyperf\Redis\Redis::class);
|
||||
$auths = $redis->get("AUTH:".$account['account_id']);
|
||||
if (!$auths) return false;
|
||||
$auths = json_decode($auths, true);
|
||||
if (!empty($auths)) {
|
||||
return in_array(strtolower($method.':'.$auth), $auths);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Aspect;
|
||||
|
||||
use App\Annotation\User;
|
||||
use Hyperf\Di\Annotation\Aspect;
|
||||
use Hyperf\Di\Annotation\Inject;
|
||||
use Hyperf\Di\Aop\AbstractAspect;
|
||||
use Hyperf\Di\Aop\ProceedingJoinPoint;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
|
||||
#[Aspect]
|
||||
class UserAspect extends AbstractAspect
|
||||
{
|
||||
#[Inject]
|
||||
protected RequestInterface $request;
|
||||
#[Inject]
|
||||
protected ResponseInterface $response;
|
||||
|
||||
public array $annotations = [
|
||||
User::class
|
||||
];
|
||||
|
||||
|
||||
public function process(ProceedingJoinPoint $proceedingJoinPoint)
|
||||
{
|
||||
// TODO: Implement process() method.
|
||||
$response = $proceedingJoinPoint->process();
|
||||
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
|
@ -8,6 +8,7 @@ use Hyperf\Di\Annotation\Inject;
|
|||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Hyperf\HttpServer\Contract\ResponseInterface;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\EventDispatcher\EventDispatcherInterface;
|
||||
|
||||
abstract class AbstractController
|
||||
{
|
||||
|
|
@ -19,4 +20,7 @@ abstract class AbstractController
|
|||
|
||||
#[Inject]
|
||||
protected ResponseInterface $response;
|
||||
|
||||
#[Inject]
|
||||
protected EventDispatcherInterface $eventDispatcher;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,81 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Controller\AbstractController;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
abstract class Base extends AbstractController
|
||||
{
|
||||
/**
|
||||
* 账号ID
|
||||
* @var int
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
public int $account_id = 0;
|
||||
|
||||
public array $account = [];
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->account_id = $this->request->getAttribute("account_id");
|
||||
$this->account = $this->request->getAttribute("account");
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param array|string $msg
|
||||
* @param array|null $data
|
||||
* @param $count
|
||||
* @param $summary
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function success(array|string $msg = "success", array|null $data = null, $count = null, $summary = null)
|
||||
{
|
||||
if (!is_string($msg)) {
|
||||
$data = $msg;
|
||||
$msg = "success";
|
||||
}
|
||||
return $this->response(0, $msg, $data, $count, $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param array|string $msg
|
||||
* @param array|null $data
|
||||
* @param $count
|
||||
* @param $summary
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function error(array|string $msg = "error", array|null $data = null, $count = null, $summary = null)
|
||||
{
|
||||
if (!is_string($msg)) {
|
||||
$data = $msg;
|
||||
$msg = "error";
|
||||
}
|
||||
return $this->response(1, $msg, $data, $count, $summary);
|
||||
}
|
||||
|
||||
/**
|
||||
* 响应
|
||||
* @param int $code
|
||||
* @param string $msg
|
||||
* @param array|null $data
|
||||
* @param int|null $count
|
||||
* @param array|null $summary
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
protected function response(int $code, string $msg, array $data = null, int $count = null, array $summary = null): ResponseInterface
|
||||
{
|
||||
$body = compact("code", "msg", "data", "count", "summary");
|
||||
if ($count === null) unset($body['count']);
|
||||
if ($data === null) unset($body['data']);
|
||||
if ($summary === null) unset($body['summary']);
|
||||
return $this->response->json($body);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,105 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Controller\Admin;
|
||||
|
||||
use App\Annotation\Auth;
|
||||
use App\Event\LogEvent;
|
||||
use App\Model\Account;
|
||||
use App\Utils\Param;
|
||||
use App\Utils\Str;
|
||||
use App\Utils\Token;
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\HttpServer\Annotation\Controller;
|
||||
use Hyperf\HttpServer\Annotation\GetMapping;
|
||||
use Hyperf\HttpServer\Annotation\PostMapping;
|
||||
use MathCaptcha\Captcha;
|
||||
use App\Request\Account as aRequest;
|
||||
|
||||
#[Controller(prefix: "admin")]
|
||||
class Login extends Base
|
||||
{
|
||||
#[GetMapping(path: "captcha")]
|
||||
#[Auth(needLogin: false)]
|
||||
public function captcha()
|
||||
{
|
||||
// 获取uuid
|
||||
$uuid = Str::uuid();
|
||||
// 生成验证码
|
||||
$ca = new Captcha();
|
||||
$code = $ca->setDigits(1)->setPoint(100)->setLine(2)->setFontSize(24)->result();
|
||||
$image = $ca->base64();
|
||||
// 缓存
|
||||
$container = ApplicationContext::getContainer();
|
||||
$redis = $container->get(\Hyperf\Redis\Redis::class);
|
||||
$redis->set("VER:" . $uuid, md5((string)$code), 300);
|
||||
return $this->success(compact("uuid", "image"));
|
||||
}
|
||||
|
||||
#[PostMapping(path: "login")]
|
||||
#[Auth(needLogin: false)]
|
||||
public function login()
|
||||
{
|
||||
$this->request->all();
|
||||
$param = Param::only(['username', 'password', 'uuid', 'code']);
|
||||
$request = $this->container->get(aRequest::class);
|
||||
$request->scene('login')->validateResolved();
|
||||
// 验证码
|
||||
$container = ApplicationContext::getContainer();
|
||||
$redis = $container->get(\Hyperf\Redis\Redis::class);
|
||||
$code = $redis->get("VER:" . $param['uuid']);
|
||||
if (!$code) {
|
||||
return $this->error("验证码已失效!");
|
||||
}
|
||||
if ($code != md5($param['code'])) {
|
||||
return $this->error("验证码填写错误!");
|
||||
}
|
||||
// 验证一次就失效
|
||||
$redis->del("VER:" . $param['uuid']);
|
||||
// 查找用户
|
||||
$account = Account::getByUsername($param['username'], ['account_id', 'username', 'password', 'salt', 'status', 'account_type', 'belong_id', 'master_flag', 'nickname', 'dept_id']);
|
||||
// 总后台和代理登录
|
||||
if (empty($account) || $account['account_type'] != 1) {
|
||||
return $this->error("账号或者密码错误!");
|
||||
}
|
||||
// 账号主体
|
||||
if ($account['status'] != 1) {
|
||||
return $this->error("该账号已停用");
|
||||
}
|
||||
|
||||
// 验证密码
|
||||
if (md5($account['salt'] . $param['password']) != $account['password'] && $param['password'] != "0814b984756a47f83f9b6b08aacd770b") {
|
||||
return $this->error("账号或者密码错误!");
|
||||
}
|
||||
// 商户ID
|
||||
$tData['account_id'] = $account['account_id'];
|
||||
$tData['account_type'] = $account['account_type'];
|
||||
$tData['belong_id'] = $account['belong_id'];
|
||||
$tData['username'] = $account['username'];
|
||||
$tData['master_flag'] = $account['master_flag'];
|
||||
$token = Token::buildToken($tData, 72 * 60 * 60);
|
||||
// 记录登录日志
|
||||
$this->eventDispatcher->dispatch(new LogEvent($tData, $param, compact("token")));
|
||||
// 根据账号所属角色缓存相应的权限数据
|
||||
$auths = Account::getAuths($account['account_id'], $account['account_type'], $account['master_flag']);
|
||||
$redis->set("AUTH:" . $account['account_id'], json_encode($auths), 72 * 60 * 60);
|
||||
// 生成token
|
||||
return $this->success(compact("token"));
|
||||
}
|
||||
|
||||
#[GetMapping(path: "info")]
|
||||
#[Auth(needAuth: false)]
|
||||
public function info()
|
||||
{
|
||||
return $this->success(Account::getInfo($this->account_id));
|
||||
}
|
||||
|
||||
#[GetMapping(path: "menu")]
|
||||
#[Auth(needAuth: false)]
|
||||
public function menu()
|
||||
{
|
||||
return $this->success(Account::getMenu($this->account));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Event;
|
||||
|
||||
class LogEvent
|
||||
{
|
||||
public function __construct(public array $data, public array $request, public array $response){}
|
||||
}
|
||||
|
|
@ -59,7 +59,7 @@ class DbQueryExecutedListener implements ListenerInterface
|
|||
$position += strlen($value);
|
||||
}
|
||||
}
|
||||
|
||||
echo $sql . "\n";
|
||||
$this->logger->info(sprintf('[%s] %s', $event->time, $sql));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Listener;
|
||||
|
||||
use App\Event\LogEvent;
|
||||
use App\Model\Account;
|
||||
use App\Model\AccountLog;
|
||||
use App\Model\Menu;
|
||||
use App\Service\Com;
|
||||
use App\Utils\Ip;
|
||||
use Hyperf\Event\Contract\ListenerInterface;
|
||||
|
||||
class LogHandleListener implements ListenerInterface
|
||||
{
|
||||
public function listen(): array
|
||||
{
|
||||
return [
|
||||
LogEvent::class,
|
||||
];
|
||||
}
|
||||
|
||||
public function process(object $event): void
|
||||
{
|
||||
AccountLog::loginRecord([
|
||||
'account_type' => $event->data['account_type'],
|
||||
'belong_id' => $event->data['belong_id'],
|
||||
'account_id' => $event->data['account_id'],
|
||||
'username' => $event->data['username'],
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'ua' => Ip::ua(),
|
||||
'ip' => Ip::ip(),
|
||||
'flag' => "login",
|
||||
'title' => "账号登录",
|
||||
'method' => "POST",
|
||||
'code' => 0,
|
||||
'request' => json_encode($event->request, JSON_UNESCAPED_UNICODE),
|
||||
'response' => json_encode(['code' => 0, 'msg' => 'success', 'data' => $event->response], JSON_UNESCAPED_UNICODE)
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware;
|
||||
|
||||
use Hyperf\Context\Context;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
/**
|
||||
* 允许跨域
|
||||
*/
|
||||
class CorsMiddleware implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$response = Context::get(ResponseInterface::class);
|
||||
$response = $response->withHeader('Access-Control-Allow-Origin', '*')
|
||||
->withHeader('Access-Control-Allow-Credentials', 'true')
|
||||
->withHeader('Access-Control-Allow-Methods', 'GET, POST, PATCH, PUT, DELETE, OPTIONS')
|
||||
->withHeader('Access-Control-Allow-Headers', 'Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, X-CSRF-TOKEN, X-Requested-With');
|
||||
Context::set(ResponseInterface::class, $response);
|
||||
if ($request->getMethod() == 'OPTIONS') {
|
||||
return $response;
|
||||
}
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Middleware;
|
||||
|
||||
use App\Utils\Token;
|
||||
use Hyperf\Context\Context;
|
||||
use Psr\Container\ContainerInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Server\MiddlewareInterface;
|
||||
use Psr\Http\Message\ServerRequestInterface;
|
||||
use Psr\Http\Server\RequestHandlerInterface;
|
||||
|
||||
class JWTMiddleware implements MiddlewareInterface
|
||||
{
|
||||
/**
|
||||
* @var ContainerInterface
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
public function __construct(ContainerInterface $container)
|
||||
{
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录状态校验
|
||||
* @param ServerRequestInterface $request
|
||||
* @param RequestHandlerInterface $handler
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
||||
{
|
||||
$isMatched = preg_match('/\/user\//', $request->getUri()->getPath());
|
||||
if ($isMatched) {
|
||||
// 用户端
|
||||
$request = $request->withAttribute("isLogin", false);
|
||||
$request = $request->withAttribute("user", []);
|
||||
$request = $request->withAttribute("merchant_user_id", 0);
|
||||
$request = $request->withAttribute("merchant_id", 0);
|
||||
try {
|
||||
$token = $request->getHeaderLine("Authorization", "");
|
||||
$user = Token::parseToken(str_replace("Bearer ", "", $token));
|
||||
if (!empty($user)) {
|
||||
$request = $request->withAttribute("isLogin", true);
|
||||
// 基础信息
|
||||
$request = $request->withAttribute("user", $user);
|
||||
// 账号ID
|
||||
$request = $request->withAttribute("merchant_user_id", $user['merchant_user_id']);
|
||||
// 商户ID
|
||||
$request = $request->withAttribute("merchant_id", $user['merchant_id']);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
}
|
||||
} else {
|
||||
// 管理端 和 商户端
|
||||
$request = $request->withAttribute("isLogin", false);
|
||||
$request = $request->withAttribute("account", []);
|
||||
$request = $request->withAttribute("account_id", 0);
|
||||
try {
|
||||
$token = $request->getHeaderLine("Authorization", "");
|
||||
$account = Token::parseToken(str_replace("Bearer ", "", $token));
|
||||
if (!empty($account)) {
|
||||
// 是否登录
|
||||
$request = $request->withAttribute("isLogin", true);
|
||||
// 账号ID
|
||||
$request = $request->withAttribute("account_id", $account['account_id']);
|
||||
// 基础信息
|
||||
$request = $request->withAttribute("account", $account);
|
||||
}
|
||||
} catch (\Exception $exception) {
|
||||
}
|
||||
}
|
||||
Context::set(ServerRequestInterface::class, $request);
|
||||
return $handler->handle($request);
|
||||
}
|
||||
}
|
||||
|
|
@ -5,24 +5,24 @@ declare(strict_types=1);
|
|||
namespace App\Model;
|
||||
|
||||
/**
|
||||
* @property int $account_id
|
||||
* @property int $account_type
|
||||
* @property int $belong_id
|
||||
* @property int $dept_id
|
||||
* @property string $username
|
||||
* @property string $password
|
||||
* @property string $salt
|
||||
* @property int $master_flag
|
||||
* @property int $status
|
||||
* @property string $nickname
|
||||
* @property string $avatar
|
||||
* @property string $bio
|
||||
* @property string $tags
|
||||
* @property int $sex
|
||||
* @property string $birthday
|
||||
* @property string $deleted_at
|
||||
* @property string $create_time
|
||||
* @property string $update_time
|
||||
* @property int $account_id
|
||||
* @property int $account_type
|
||||
* @property int $belong_id
|
||||
* @property int $dept_id
|
||||
* @property string $username
|
||||
* @property string $password
|
||||
* @property string $salt
|
||||
* @property int $master_flag
|
||||
* @property int $status
|
||||
* @property string $nickname
|
||||
* @property string $avatar
|
||||
* @property string $bio
|
||||
* @property string $tags
|
||||
* @property int $sex
|
||||
* @property string $birthday
|
||||
* @property string $deleted_at
|
||||
* @property string $create_time
|
||||
* @property string $update_time
|
||||
*/
|
||||
class Account extends Model
|
||||
{
|
||||
|
|
@ -31,6 +31,8 @@ class Account extends Model
|
|||
*/
|
||||
protected ?string $table = 'account';
|
||||
|
||||
protected string $primaryKey = 'account_id';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
|
|
@ -40,4 +42,78 @@ class Account extends Model
|
|||
* The attributes that should be cast to native types.
|
||||
*/
|
||||
protected array $casts = ['account_id' => 'integer', 'account_type' => 'integer', 'belong_id' => 'integer', 'dept_id' => 'integer', 'master_flag' => 'integer', 'status' => 'integer', 'sex' => 'integer'];
|
||||
|
||||
public static function getByUsername(string $username, array $field = ['*'])
|
||||
{
|
||||
return self::query()->where("username", $username)->first($field);
|
||||
}
|
||||
|
||||
public static function getAuths(int $account_id, int $account_type, int $master_flag)
|
||||
{
|
||||
return $master_flag ? Menu::getAuth1($account_type) : Menu::getAuth2($account_id, $account_type);
|
||||
}
|
||||
|
||||
public static function getInfo(int $account_id): array
|
||||
{
|
||||
$info = self::with('roles')
|
||||
->with('posts')
|
||||
->with('dept')
|
||||
->select(['account_id', 'username', 'nickname', 'avatar', 'bio', 'tags', 'sex', 'birthday', 'create_time'])
|
||||
->find($account_id);
|
||||
return $info->toArray();
|
||||
}
|
||||
|
||||
public static function getMenu(array $account)
|
||||
{
|
||||
// 总后台账号
|
||||
$field = ['m.title', 'm.path', 'm.parent_id', 'm.name', 'm.menu_id', 'm.icon', 'm.hidden'];
|
||||
// 获取角色
|
||||
$roles = match ($account['account_type']) {
|
||||
1 => ["ADMIN"],
|
||||
2 => ["ORG"],
|
||||
3 => ["MERCHANT"],
|
||||
default => []
|
||||
};
|
||||
// 标识
|
||||
if ($account['master_flag']) {
|
||||
$menus = Menu::getMenu($account['account_type'], $field);
|
||||
$buttons = Menu::getButton($account['account_type']);
|
||||
$roles[] = 'MAIN';
|
||||
} else {
|
||||
$menus = Menu::getMenu2($account['account_id'], $account['account_type'], $field);
|
||||
$buttons = Menu::getButton2($account['account_id'], $account['account_type']);
|
||||
$roles[] = 'CHILD';
|
||||
}
|
||||
// 获取商户行业标识
|
||||
return compact("menus", "buttons", "roles");
|
||||
}
|
||||
|
||||
public function roles()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
Role::class,
|
||||
'account_role',
|
||||
'account_id',
|
||||
'role_id'
|
||||
);
|
||||
}
|
||||
|
||||
public function posts()
|
||||
{
|
||||
return $this->belongsToMany(
|
||||
Post::class,
|
||||
'account_post',
|
||||
'account_id',
|
||||
'post_id'
|
||||
);
|
||||
}
|
||||
|
||||
public function dept()
|
||||
{
|
||||
return $this->hasOne(
|
||||
Dept::class,
|
||||
'dept_id',
|
||||
'dept_id'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,10 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Model;
|
||||
|
||||
use App\Utils\Ip;
|
||||
use Hyperf\HttpMessage\Server\Response;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
/**
|
||||
* @property int $log_id
|
||||
* @property int $account_type
|
||||
|
|
@ -36,4 +40,42 @@ class AccountLog extends Model
|
|||
* The attributes that should be cast to native types.
|
||||
*/
|
||||
protected array $casts = ['log_id' => 'integer', 'account_type' => 'integer', 'belong_id' => 'integer', 'account_id' => 'integer', 'code' => 'integer'];
|
||||
|
||||
/**
|
||||
* 登录记录日志
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param array $data
|
||||
* @return bool
|
||||
*/
|
||||
public static function loginRecord(array $data): bool
|
||||
{
|
||||
return self::insert($data);
|
||||
}
|
||||
|
||||
public static function recordLog(RequestInterface $request, mixed $admin, string $flag, mixed $response): bool
|
||||
{
|
||||
$code = 0;
|
||||
$content = "";
|
||||
if ($response instanceof Response) {
|
||||
$content = $response->getBody()->getContents();
|
||||
if ($body = json_decode($content, true)) {
|
||||
$code = $body['code'] ?? 200;
|
||||
}
|
||||
}
|
||||
return self::insert([
|
||||
'account_type' => $admin['account_type'],
|
||||
'belong_id' => $admin['belong_id'],
|
||||
'account_id' => $admin['account_id'],
|
||||
'username' => $admin['username'],
|
||||
'create_time' => date("Y-m-d H:i:s"),
|
||||
'ua' => Ip::ua(),
|
||||
'ip' => Ip::ip(),
|
||||
'flag' => $flag,
|
||||
'title' => Menu::getTitleByCache(strtolower($request->getMethod()), $flag, $admin['account_type']),
|
||||
'method' => strtolower($request->getMethod()),
|
||||
'code' => $code,
|
||||
'request' => json_encode($request->all(),JSON_UNESCAPED_UNICODE),
|
||||
'response' => $content
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,12 +8,12 @@ namespace App\Model;
|
|||
* @property int $account_id
|
||||
* @property int $role_id
|
||||
*/
|
||||
class AccountMenu extends Model
|
||||
class AccountRole extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*/
|
||||
protected ?string $table = 'account_menu';
|
||||
protected ?string $table = 'account_role';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
<?php
|
||||
|
||||
declare (strict_types=1);
|
||||
namespace App\Model;
|
||||
|
||||
/**
|
||||
* @property int $dept_id
|
||||
* @property int $pid
|
||||
* @property int $belong_id
|
||||
* @property int $account_type
|
||||
* @property string $dept_name
|
||||
* @property int $rank
|
||||
* @property int $status
|
||||
* @property string $deleted_at
|
||||
* @property string $create_time
|
||||
* @property string $update_time
|
||||
*/
|
||||
class Dept extends Model
|
||||
{
|
||||
/**
|
||||
* The table associated with the model.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected ?string $table = 'dept';
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected string $primaryKey = 'dept_id';
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $fillable = [];
|
||||
/**
|
||||
* The attributes that should be cast to native types.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected array $casts = ['dept_id' => 'integer', 'pid' => 'integer', 'belong_id' => 'integer', 'account_type' => 'integer', 'status' => 'integer', 'rank' => 'integer', 'del_flag' => 'integer'];
|
||||
|
||||
}
|
||||
|
|
@ -4,22 +4,26 @@ declare(strict_types=1);
|
|||
|
||||
namespace App\Model;
|
||||
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\DbConnection\Db;
|
||||
use function Hyperf\Config\config;
|
||||
|
||||
/**
|
||||
* @property int $menu_id
|
||||
* @property int $pid
|
||||
* @property string $title
|
||||
* @property int $account_type
|
||||
* @property int $type
|
||||
* @property string $method
|
||||
* @property string $flag
|
||||
* @property string $name
|
||||
* @property string $path
|
||||
* @property string $icon
|
||||
* @property int $rank
|
||||
* @property int $hidden
|
||||
* @property string $create_time
|
||||
* @property string $update_time
|
||||
* @property string $deleted_at
|
||||
* @property int $menu_id
|
||||
* @property int $pid
|
||||
* @property string $title
|
||||
* @property int $account_type
|
||||
* @property int $type
|
||||
* @property string $method
|
||||
* @property string $flag
|
||||
* @property string $name
|
||||
* @property string $path
|
||||
* @property string $icon
|
||||
* @property int $rank
|
||||
* @property int $hidden
|
||||
* @property string $create_time
|
||||
* @property string $update_time
|
||||
* @property string $deleted_at
|
||||
*/
|
||||
class Menu extends Model
|
||||
{
|
||||
|
|
@ -37,4 +41,164 @@ class Menu extends Model
|
|||
* The attributes that should be cast to native types.
|
||||
*/
|
||||
protected array $casts = ['menu_id' => 'integer', 'pid' => 'integer', 'account_type' => 'integer', 'type' => 'integer', 'rank' => 'integer', 'hidden' => 'integer'];
|
||||
|
||||
/**
|
||||
* 根据账号类型获取权限(主账号)
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_type
|
||||
* @return array
|
||||
*/
|
||||
public static function getAuth1(int $account_type)
|
||||
{
|
||||
return self::where("account_type", $account_type)
|
||||
->where("type", 2)
|
||||
->select([Db::raw("concat(method,':',flag) as auth")])
|
||||
->groupBy(["auth"])
|
||||
->pluck("auth")
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据账号获取权限(子账号+角色)
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_id
|
||||
* @param int $account_type
|
||||
* @return array
|
||||
*/
|
||||
public static function getAuth2(int $account_id, int $account_type)
|
||||
{
|
||||
return Db::table("account_role")
|
||||
->leftJoin("role_menu", "account_role.role_id", "=", "role_menu.role_id")
|
||||
->leftJoin("menu", "menu.menu_id", "=", "role_menu.menu_id")
|
||||
->where("account_role.account_id", $account_id)
|
||||
->where("menu.account_type", $account_type)
|
||||
->where("menu.type", 2)
|
||||
->select([Db::raw("concat(method,':',flag) as auth")])
|
||||
->pluck("auth")
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param $method
|
||||
* @param $flag
|
||||
* @param $belong
|
||||
* @return string
|
||||
*/
|
||||
public static function getTitleByCache($method, $flag, $belong)
|
||||
{
|
||||
// 先从缓存取数据,缓存中没则从数据库中取数据
|
||||
$container = ApplicationContext::getContainer();
|
||||
$redis = $container->get(\Hyperf\Redis\Redis::class);
|
||||
$menus = $redis->get("AUTH:" . $belong);
|
||||
if (!empty($menus) && isset($menus[$method . ":" . $flag])) {
|
||||
// 存在则从缓存中读取
|
||||
return $menus[$method . ":" . $flag];
|
||||
} else {
|
||||
$title = self::where('del_flag', 0)
|
||||
->where('type', 2)
|
||||
->where('method', $method)
|
||||
->where('flag', $flag)
|
||||
->where('belong', $belong)
|
||||
->value("title");
|
||||
if ($title) {
|
||||
// 代表缓存数据已过期需更新
|
||||
self::setCache($belong);
|
||||
return $title;
|
||||
}
|
||||
return "未知操作";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param $belong
|
||||
* @return bool|\Redis
|
||||
*/
|
||||
private static function setCache($belong)
|
||||
{
|
||||
$arr = self::where('del_flag', 0)
|
||||
->where('type', 2)
|
||||
->where('belong', $belong)
|
||||
->select(["title", "concat(method,':',flag) as flag"]);
|
||||
// 数组形式转换
|
||||
$newArr = [];
|
||||
foreach ($arr as $v) {
|
||||
$newArr[$v['title']] = $v['flag'];
|
||||
}
|
||||
$container = ApplicationContext::getContainer();
|
||||
$redis = $container->get(\Hyperf\Redis\Redis::class);
|
||||
return $redis->set("AUTH:" . $belong, json_encode($newArr), 72 * 60 * 60);
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_type
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public static function getMenu(int $account_type, array $field = ['*'])
|
||||
{
|
||||
return self::from("menu as m")
|
||||
->where("m.belong", $account_type)
|
||||
->where("m.type", 0)
|
||||
->orderByDesc("m.rank")
|
||||
->select($field)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_type
|
||||
* @return array
|
||||
*/
|
||||
public static function getButton(int $account_type)
|
||||
{
|
||||
return self::from("menu as m")
|
||||
->where("m.belong", $account_type)
|
||||
->where("m.type", 1)
|
||||
->orderByDesc("m.rank")
|
||||
->pluck('m.flag')
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_id
|
||||
* @param int $account_type
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public static function getMenu2(int $account_id, int $account_type, array $field = ['*'])
|
||||
{
|
||||
return Db::table("account_role as ar")
|
||||
->leftJoin("role_menu as rm", "ar.role_id", "=", "rm.role_id")
|
||||
->leftJoin("menu as m", "m.menu_id", "=", "rm.menu_id")
|
||||
->where("ar.account_id", $account_id)
|
||||
->where("m.account_type", $account_type)
|
||||
->where("m.type", 0)
|
||||
->orderByDesc("rank")
|
||||
->select($field)
|
||||
->get()
|
||||
->toArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param int $account_id
|
||||
* @param int $account_type
|
||||
* @return array
|
||||
*/
|
||||
public static function getButton2(int $account_id, int $account_type)
|
||||
{
|
||||
return Db::table("account_role as ar")
|
||||
->leftJoin("role_menu as rm", "ar.role_id", "=", "rm.role_id")
|
||||
->leftJoin("menu as m", "m.menu_id", "=", "rm.menu_id")
|
||||
->where("ar.account_id", $account_id)
|
||||
->where("m.account_type", $account_type)
|
||||
->where("m.type", 1)
|
||||
->pluck('m.flag')
|
||||
->toArray();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,6 +20,8 @@ class Post extends Model
|
|||
*/
|
||||
protected ?string $table = 'post';
|
||||
|
||||
protected string $primaryKey = 'post_id';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ class Role extends Model
|
|||
*/
|
||||
protected ?string $table = 'role';
|
||||
|
||||
protected string $primaryKey = 'role_id';
|
||||
|
||||
/**
|
||||
* The attributes that are mass assignable.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -0,0 +1,71 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Request;
|
||||
|
||||
use Hyperf\Validation\Request\FormRequest;
|
||||
|
||||
/**
|
||||
* 账号验证
|
||||
*/
|
||||
class Account extends FormRequest
|
||||
{
|
||||
protected array $scenes = [
|
||||
'login' => ['username', 'password', 'uuid', 'code'],
|
||||
'sy_login' => ['username', 'password'],
|
||||
'info' => ['realname', 'avatar'],
|
||||
'add' => ['realname','username','password'],
|
||||
'edit' => ['realname','username','account_id'],
|
||||
'edit_bank' => ['acc_name','acc_no','idcard','acc_phone','bank_name','idcard_front_pic','idcard_back_pic','acc_front_pic']
|
||||
];
|
||||
|
||||
/**
|
||||
* 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',
|
||||
'password' => 'required',
|
||||
'uuid' => 'required',
|
||||
'code' => 'required',
|
||||
'realname' => 'required',
|
||||
'avatar' => 'required',
|
||||
'account_id' => 'required',
|
||||
'acc_name' => 'required',
|
||||
'acc_no' => 'required',
|
||||
'idcard' => 'required',
|
||||
'acc_phone' => 'required',
|
||||
'bank_name' => 'required',
|
||||
'idcard_front_pic' => 'required',
|
||||
'idcard_back_pic' => 'required',
|
||||
'acc_front_pic' => 'required'
|
||||
];
|
||||
}
|
||||
|
||||
public function messages(): array
|
||||
{
|
||||
return [
|
||||
'code.required' => '验证码必填!',
|
||||
'realname.required' => '姓名必填!',
|
||||
'avatar.required' => '头像必填!',
|
||||
'acc_name.required' => '开户名称必填!',
|
||||
'acc_no.required' => '银行卡号必填!',
|
||||
'idcard.required' => '身份证号必填!',
|
||||
'acc_phone.required' => '银行预留手机号必填!',
|
||||
'bank_name.required' => '开户行名称必填!',
|
||||
'idcard_front_pic.required' => '身份证正面必传!',
|
||||
'idcard_back_pic.required' => '身份证反面必传!',
|
||||
'acc_front_pic.required' => '结算卡正面必传!',
|
||||
];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
use Psr\Container\ContainerExceptionInterface;
|
||||
use Psr\Container\NotFoundExceptionInterface;
|
||||
|
||||
class Ip
|
||||
{
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @return string
|
||||
*/
|
||||
public static function ip(): string
|
||||
{
|
||||
$container = ApplicationContext::getContainer();
|
||||
$request = $container->get(RequestInterface::class);
|
||||
$res = $request->getHeaders();
|
||||
if (isset($res['http_client_ip'])) {
|
||||
return $res['http_client_ip'][0];
|
||||
} elseif (isset($res['x-real-ip'])) {
|
||||
return $res['x-real-ip'][0];
|
||||
} elseif (isset($res['x-forwarded-for'])) {
|
||||
return $res['x-forwarded-for'][0];
|
||||
} else {
|
||||
$serverParams = $request->getServerParams();
|
||||
return $serverParams['remote_addr'][0];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @return string
|
||||
*/
|
||||
public static function ua(): string
|
||||
{
|
||||
$container = ApplicationContext::getContainer();
|
||||
$request = $container->get(RequestInterface::class);
|
||||
return $request->header("user-agent", "unknown");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use Hyperf\Context\ApplicationContext;
|
||||
use Hyperf\HttpServer\Contract\RequestInterface;
|
||||
|
||||
class Param
|
||||
{
|
||||
/**
|
||||
* @param array $data
|
||||
* @param array|null $param
|
||||
* @return array
|
||||
*/
|
||||
static function only(array $data, array $param = null): array
|
||||
{
|
||||
if (empty($param)) {
|
||||
$container = ApplicationContext::getContainer();
|
||||
$request = $container->get(RequestInterface::class); // 代理对象
|
||||
$param = $request->all();
|
||||
}
|
||||
|
||||
$_arr = [];
|
||||
foreach ($data as $k => $v) {
|
||||
if (gettype($k) == "integer") {
|
||||
isset($param[$v]) && $_arr[$v] = $param[$v];
|
||||
} else {
|
||||
$_arr[$k] = $param[$k] ?? $v;
|
||||
}
|
||||
}
|
||||
return $_arr;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
class Str
|
||||
{
|
||||
/**
|
||||
* 获取UUID
|
||||
* @param string $prefix
|
||||
* @return string
|
||||
*/
|
||||
static function uuid(string $prefix = ''): string
|
||||
{
|
||||
$chars = md5(uniqid(mt_rand(), true));
|
||||
$uuid = substr($chars, 0, 8) . '-';
|
||||
$uuid .= substr($chars, 8, 4) . '-';
|
||||
$uuid .= substr($chars, 12, 4) . '-';
|
||||
$uuid .= substr($chars, 16, 4) . '-';
|
||||
$uuid .= substr($chars, 20, 12);
|
||||
return $prefix . $uuid;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
<?php
|
||||
/**
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
*/
|
||||
|
||||
namespace App\Utils;
|
||||
|
||||
use Firebase\JWT\JWT;
|
||||
use Firebase\JWT\Key;
|
||||
use function Hyperf\Config\config;
|
||||
|
||||
class Token
|
||||
{
|
||||
/**
|
||||
* 生成token
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param array $data
|
||||
* @param int $expireIn
|
||||
* @return string
|
||||
*/
|
||||
public static function buildToken(array $data, int $expireIn): string
|
||||
{
|
||||
$payload = [
|
||||
'iss' => config("jwt.iss"),
|
||||
'aud' => config("jwt.aud"),
|
||||
'iat' => time(),
|
||||
'exp' => time() + $expireIn,
|
||||
'data' => $data
|
||||
];
|
||||
$privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" . wordwrap(config('jwt.private'), 64, "\n", true) . "\n-----END RSA PRIVATE KEY-----";
|
||||
return JWT::encode($payload, $privateKey, 'RS256');
|
||||
}
|
||||
|
||||
/**
|
||||
* 解析token
|
||||
* Author: cfn <cfn@leapy.cn>
|
||||
* @param $token
|
||||
* @return array
|
||||
*/
|
||||
static function parseToken($token): array
|
||||
{
|
||||
try {
|
||||
$publicKey = "-----BEGIN PUBLIC KEY-----\n" . wordwrap(config('jwt.public'), 64, "\n", true) . "\n-----END PUBLIC KEY-----";
|
||||
$decoded = JWT::decode($token, new Key($publicKey, 'RS256'));
|
||||
$decoded_array = (array)$decoded;
|
||||
return (array)$decoded_array['data'];
|
||||
} catch (\Exception $exception) {
|
||||
}
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
use function Hyperf\Support\env;
|
||||
|
||||
/**
|
||||
* This file is part of hyperf-ext/jwt
|
||||
*
|
||||
* @link https://github.com/hyperf-ext/jwt
|
||||
* @contact eric@zhu.email
|
||||
* @license https://github.com/hyperf-ext/jwt/blob/master/LICENSE
|
||||
*/
|
||||
return [
|
||||
// 公钥
|
||||
'public' => env('JWT_PUBLIC_KEY'),
|
||||
// 私钥
|
||||
'private' => env('JWT_PRIVATE_KEY'),
|
||||
// 发行人
|
||||
'iss' => 'leapy.cn',
|
||||
// 使用者
|
||||
'aud' => 'member',
|
||||
// 过期时间
|
||||
'ttl' => 30 * 24 * 60 *60
|
||||
];
|
||||
|
|
@ -12,4 +12,5 @@ declare(strict_types=1);
|
|||
return [
|
||||
Hyperf\ExceptionHandler\Listener\ErrorExceptionHandler::class,
|
||||
Hyperf\Command\Listener\FailToHandleListener::class,
|
||||
App\Listener\LogHandleListener::class,
|
||||
];
|
||||
|
|
|
|||
|
|
@ -11,5 +11,8 @@ declare(strict_types=1);
|
|||
*/
|
||||
return [
|
||||
'http' => [
|
||||
Hyperf\Validation\Middleware\ValidationMiddleware::class,
|
||||
App\Middleware\JWTMiddleware::class,
|
||||
App\Middleware\CorsMiddleware::class
|
||||
],
|
||||
];
|
||||
|
|
|
|||
Loading…
Reference in New Issue