Files
hdk-admin/src/Middleware/PermissionMiddleware.php

167 lines
5.1 KiB
PHP
Raw Normal View History

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