From 1c86f7c2780388c1bafb8dd368bbedecf3b0703e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=8E=E4=B8=9C=E4=BA=91?= Date: Wed, 5 Jul 2023 16:54:27 +0800 Subject: [PATCH] =?UTF-8?q?feat(middleware):=20=E6=B7=BB=E5=8A=A0=E4=BA=86?= =?UTF-8?q?=E7=94=A8=E4=BA=8E=E6=9B=BF=E4=BB=A3=E5=8E=9F=E7=94=9F=20Sessio?= =?UTF-8?q?nMiddleware=20=E7=9A=84=E7=B1=BB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 只有已登录的 Session 才保存 --- src/Middleware/SessionMiddleware.php | 160 +++++++++++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 src/Middleware/SessionMiddleware.php diff --git a/src/Middleware/SessionMiddleware.php b/src/Middleware/SessionMiddleware.php new file mode 100644 index 0000000..70c9674 --- /dev/null +++ b/src/Middleware/SessionMiddleware.php @@ -0,0 +1,160 @@ + + * Powered by PhpStorm + * Created on 2023/3/8 + */ + +namespace Singularity\HDK\Auth\Middleware; + +use Carbon\Carbon; +use Hyperf\Contract\ConfigInterface; +use Hyperf\Contract\SessionInterface; +use Hyperf\HttpMessage\Cookie\Cookie; +use Hyperf\HttpMessage\Server\Response; +use Hyperf\Session\SessionManager; +use Psr\Http\Message\RequestInterface; +use Psr\Http\Message\ResponseInterface; +use Psr\Http\Message\ServerRequestInterface; +use Psr\Http\Server\MiddlewareInterface; +use Psr\Http\Server\RequestHandlerInterface; + +/** + * Singularity\HDK\Auth\Middleware\SessionMiddleware@HDK-Core + * + * @author 李东云 + * Powered by PhpStorm + * Created on 2023/3/8 + */ +class SessionMiddleware implements MiddlewareInterface +{ + public function __construct(private SessionManager $sessionManager, private ConfigInterface $config) + { + } + + /** + * Process an incoming server request. + * Processes an incoming server request in order to produce a response. + * If unable to produce the response itself, it may delegate to the provided + * request handler to do so. + */ + public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface + { + if (!$this->isSessionAvailable()) { + return $handler->handle($request); + } + + $session = $this->sessionManager->start($request); + + try { + $response = $handler->handle($request); + } finally { + $this->storeCurrentUrl($request, $session); + $session = $this->sessionManager->getSession(); + + /* + * 现在的机制,但凡写入 Redis 的数据, + * 过期时间就是固定的 gc_maxlifetime + * + * 而 RedisHandler 只会被依赖注入时加载一次, + * 后续无法临时修改 gc_maxlifetime + * + * 又因为现在没有其他情况用到 session + * 只有登录之后才会记下用户信息 + * + * 所以一个妥协的方案,就是只有登录了再写入 Redis + * + * (除非重写整套 RedisHandler/RedisHandlerFactory/...) + */ + if (!$this->auth($session)) { + $this->sessionManager->end($session); + } + } + + return $this->addCookieToResponse($request, $response, $session); + } + + private function isSessionAvailable(): bool + { + return $this->config->has('session.handler'); + } + + /** + * Store the current URL for the request if necessary. + */ + private function storeCurrentUrl(RequestInterface $request, SessionInterface $session) + { + if ($request->getMethod() === 'GET') { + $session->setPreviousUrl($this->fullUrl($request)); + } + } + + /** + * Add the session cookie to the response·. + */ + private function addCookieToResponse( + ServerRequestInterface $request, + ResponseInterface $response, + SessionInterface $session + ): ResponseInterface { + $cookie = new Cookie( + name: $session->getName(), + value: $session->getId(), + expire: $this->getCookieExpirationDate($session), + path: $this->config->get('session.options.path', '/'), + domain: $this->config->get('session.options.domain', $request->getUri()->getHost()), + secure: $this->config->get( + 'session.options.secure', + strtolower($request->getUri()->getScheme()) === 'https' + ), + httpOnly: true, + sameSite: $this->config->get('session.options.samesite', Cookie::SAMESITE_LAX) + ); + if (!method_exists($response, 'withCookie')) { + return $response->withHeader('Set-Cookie', (string)$cookie); + } + /* @var Response $response */ + return $response->withCookie($cookie); + } + + /** + * Get the full URL for the request. + */ + private function fullUrl(RequestInterface $request): string + { + $uri = $request->getUri(); + $query = $uri->getQuery(); + $question = $uri->getHost() . $uri->getPath() == '/' ? '/?' : '?'; + return $query ? $this->url($request) . $question . $query : $this->url($request); + } + + /** + * Get the session lifetime in seconds. + */ + private function getCookieExpirationDate(SessionInterface $session): int + { + // if ($this->config->get('session.options.expire_on_close')) { + if (!$this->auth($session)) { + $expirationDate = 0; + } else { + $expireSeconds = $this->config->get('session.options.cookie_lifetime', 5 * 60 * 60); + $expirationDate = Carbon::now()->addSeconds($expireSeconds)->getTimestamp(); + } + return $expirationDate; + } + + /** + * Get the URL (no query string) for the request. + */ + private function url(RequestInterface $request): string + { + return rtrim(preg_replace('/\?.*/', '', (string)$request->getUri())); + } + + private function auth(SessionInterface $session) + { + return $session->has('userInfo'); + } +}