167 lines
5.1 KiB
PHP
167 lines
5.1 KiB
PHP
|
|
<?php
|
|||
|
|
/**
|
|||
|
|
* hyperf_admin 鉴权中间件
|
|||
|
|
* 统一负责 资源权限校验
|
|||
|
|
*/
|
|||
|
|
namespace HyperfAdmin\Admin\Middleware;
|
|||
|
|
|
|||
|
|
use Hyperf\HttpServer\Contract\RequestInterface;
|
|||
|
|
use Hyperf\HttpServer\Contract\ResponseInterface as HttpResponse;
|
|||
|
|
use Hyperf\HttpServer\CoreMiddleware;
|
|||
|
|
use Hyperf\Logger\LoggerFactory;
|
|||
|
|
use HyperfAdmin\Admin\Service\AuthService;
|
|||
|
|
use HyperfAdmin\Admin\Service\ModuleProxy;
|
|||
|
|
use HyperfAdmin\Admin\Service\PermissionService;
|
|||
|
|
use HyperfAdmin\BaseUtils\AKSK;
|
|||
|
|
use HyperfAdmin\BaseUtils\Constants\ErrorCode;
|
|||
|
|
use HyperfAdmin\BaseUtils\Log;
|
|||
|
|
use Psr\Container\ContainerInterface;
|
|||
|
|
use Psr\Http\Message\ResponseInterface;
|
|||
|
|
use Psr\Http\Message\ServerRequestInterface;
|
|||
|
|
use Psr\Http\Server\RequestHandlerInterface;
|
|||
|
|
|
|||
|
|
class PermissionMiddleware extends CoreMiddleware
|
|||
|
|
{
|
|||
|
|
/**
|
|||
|
|
* @var RequestInterface
|
|||
|
|
*/
|
|||
|
|
protected $request;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @var HttpResponse
|
|||
|
|
*/
|
|||
|
|
protected $response;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @var LoggerFactory
|
|||
|
|
*/
|
|||
|
|
protected $log;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @var PermissionService
|
|||
|
|
*/
|
|||
|
|
protected $permission_service;
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @var AuthService
|
|||
|
|
*/
|
|||
|
|
protected $auth_service;
|
|||
|
|
|
|||
|
|
public function __construct(ContainerInterface $container, HttpResponse $response, RequestInterface $request, LoggerFactory $logger)
|
|||
|
|
{
|
|||
|
|
$this->container = $container;
|
|||
|
|
$this->response = $response;
|
|||
|
|
$this->request = $request;
|
|||
|
|
$this->log = $logger->get('permission');
|
|||
|
|
$this->permission_service = make(PermissionService::class);
|
|||
|
|
$this->auth_service = make(AuthService::class);
|
|||
|
|
parent::__construct($container, 'http');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
|
|||
|
|
{
|
|||
|
|
$uri = $request->getUri();
|
|||
|
|
$path = $uri->getPath();
|
|||
|
|
$method = $request->getMethod();
|
|||
|
|
|
|||
|
|
$module_proxy = make(ModuleProxy::class);
|
|||
|
|
if ($module_proxy->needProxy()) {
|
|||
|
|
$res = $module_proxy->request();
|
|||
|
|
if (isset($res['payload']) && $res['payload'] === []) {
|
|||
|
|
$res['payload'] = (object)[];
|
|||
|
|
}
|
|||
|
|
$response = $this->response->json($res);
|
|||
|
|
Log::get('http')->info('proxy_end', [
|
|||
|
|
'module' => $module_proxy->getTargetModule(),
|
|||
|
|
'path' => $path,
|
|||
|
|
'response' => $response,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return $response;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 其他系统调用,走AKSK中间件验证
|
|||
|
|
$client_token = $request->getHeader('Authorization')[0] ?? '';
|
|||
|
|
if ($client_token) {
|
|||
|
|
if (!$this->akSkAuth($uri, $method, $client_token)) {
|
|||
|
|
return $this->fail(ErrorCode::CODE_ERR_DENY, '接口权限校验失败');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $handler->handle($request);
|
|||
|
|
}
|
|||
|
|
// 内部请求时不做鉴权
|
|||
|
|
if ($this->getRealIp() == '127.0.0.1') {
|
|||
|
|
return $handler->handle($request);
|
|||
|
|
}
|
|||
|
|
// 开放资源,不进行鉴权
|
|||
|
|
if ($this->permission_service->isOpen($path, $method)) {
|
|||
|
|
return $handler->handle($request);
|
|||
|
|
}
|
|||
|
|
// 检验登录状态
|
|||
|
|
$user = $this->auth_service->user();
|
|||
|
|
if (empty($user)) {
|
|||
|
|
return $this->fail(ErrorCode::CODE_LOGIN, '请先登录');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if (!$this->permission_service->hasPermission($path, $method)) {
|
|||
|
|
return $this->fail(ErrorCode::CODE_NO_AUTH, "{$path}权限不足");
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
return $handler->handle($request);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
protected function getRealIp()
|
|||
|
|
{
|
|||
|
|
return $this->request->header('x-real-ip');
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* @param int $code
|
|||
|
|
* @param string|null $message
|
|||
|
|
*
|
|||
|
|
* @return \Psr\Http\Message\ResponseInterface
|
|||
|
|
*/
|
|||
|
|
public function fail(int $code = -1, ?string $message = null)
|
|||
|
|
{
|
|||
|
|
$response = [
|
|||
|
|
'code' => $code,
|
|||
|
|
'message' => $message ?: ErrorCode::getMessage($code),
|
|||
|
|
'payload' => (object)[],
|
|||
|
|
];
|
|||
|
|
$this->log->warning($this->request->getUri()->getPath() . ' fail', $response);
|
|||
|
|
|
|||
|
|
return $this->response->json($response);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private function akSkAuth($uri, $method, $client_token)
|
|||
|
|
{
|
|||
|
|
$host = env('APP_DOMAIN', '');
|
|||
|
|
$query = $this->request->getQueryParams();
|
|||
|
|
if (!empty($query)) {
|
|||
|
|
ksort($query);
|
|||
|
|
$query = http_build_query($query);
|
|||
|
|
} else {
|
|||
|
|
$query = '';
|
|||
|
|
}
|
|||
|
|
$path = $uri->getPath();
|
|||
|
|
$content_type = $this->request->getHeader('Content-type')[0] ?? '';
|
|||
|
|
$body = $this->request->getParsedBody();
|
|||
|
|
if (!empty($body)) {
|
|||
|
|
ksort($body);
|
|||
|
|
$body = json_encode($body, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
|
|||
|
|
} else {
|
|||
|
|
$body = '';
|
|||
|
|
}
|
|||
|
|
$ak = str_replace('ha ', '', explode(':', $client_token)[0] ?? '');
|
|||
|
|
$sk = config('client_user')[$ak] ?? '';
|
|||
|
|
$auth = new AKSK($ak, $sk);
|
|||
|
|
$token = $auth->token($method, $path, $host, $query, $content_type, $body);
|
|||
|
|
$this->log->info('aksk auth:', [
|
|||
|
|
'client_token' => $client_token,
|
|||
|
|
'except_token' => $token,
|
|||
|
|
]);
|
|||
|
|
|
|||
|
|
return $token === $client_token;
|
|||
|
|
}
|
|||
|
|
}
|