167 lines
5.1 KiB
PHP
Executable File
167 lines
5.1 KiB
PHP
Executable File
<?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;
|
||
}
|
||
}
|