另類用法 hyperf/session 實現 API token

StringKe發表於2019-12-24

前期準備

安裝 hyperf/session 使用 redis 作為 session 儲存

我的做法

把session的id作為 api key,這樣登入的時候只要把資訊寫入session,前端傳遞id key 進來 就可以調取session裡的資訊,並且只要把id傳遞到其他客戶端只要相同key也可以調取資訊,只要redis裡的資訊沒有過期

一開始遇到的問題

session預設方法是從cookie裡拿,有點不方便,前端需要注意 cors 跨域問題然後還要傳遞cookie。

解決方法

使用 切面切入 Hyperf\Session\SessionManager::parseSessionId 獲取id的方法,魔改本方法

以下是我的程式碼

<?php

declare(strict_types=1);

namespace App\Aspect;

use Hyperf\Contract\ConfigInterface;
use Hyperf\Contract\StdoutLoggerInterface;
use Hyperf\Di\Annotation\Aspect;
use Hyperf\Di\Annotation\Inject;
use Hyperf\Di\Aop\AbstractAspect;
use Hyperf\HttpServer\Contract\RequestInterface;
use Hyperf\Redis\RedisFactory;
use Hyperf\Utils\Str;
use Psr\Container\ContainerInterface;
use Hyperf\Di\Aop\ProceedingJoinPoint;

/**
 * @Aspect
 */
class SessionAspect extends AbstractAspect
{
    /**
     * @var ContainerInterface
     */
    protected $container;

    /**
     * @Inject()
     * @var RequestInterface
     */
    protected $request;

    /**
     * @Inject()
     * @var ConfigInterface
     */
    protected $config;

    /**
     * @Inject()
     * @var StdoutLoggerInterface
     */
    protected $logger;

    /**
     * @var array
     */
    public $classes = [
        'Hyperf\Session\SessionManager::parseSessionId'
    ];

    public function __construct(ContainerInterface $container)
    {
        $this->container = $container;
    }

    public function process(ProceedingJoinPoint $proceedingJoinPoint)
    {
        $priority = $this->config->get('session.options.id_priority');
        $sessionID = null;
        // 預設從 cookie 裡獲取 ID
        if ($priority['cookie']) {
            $cookies = $this->request->getCookieParams();
            foreach ($cookies as $key => $value) {
                if ($key === $this->getSessionName()) {
                    $sessionID = (string)$value;
                }
            }
        }
        // header 獲取id
        if (isset($priority['header'])) {
            if ($this->request->hasHeader($priority['header'])) {
                $sessionID = (string)$this->request->getHeader($priority['header'])[0];
            }
        }
        // url 引數 獲取id
        if (isset($priority['get']) && $sessionID === null) {
            $params = $this->request->getQueryParams();
            if ($params && array_key_exists($priority['get'], $params)) {
                $sessionID = (string)$params[$priority['get']];
            }
        }
        if ($sessionID && strlen($sessionID) === 40) {
            $redis = $this->container->get(RedisFactory::class)->get('session');
            $existsKey = $redis->exists($sessionID);
            if ($existsKey !== 1) {
                return Str::random(40);
            }
        }
        $this->logger->notice('獲取到 ' . microtime(true) . "\t" . 'Session => ' . $sessionID);
        return $sessionID;
    }

    public function getSessionName(): string
    {
        return 'HYPERF_SESSION_ID';
    }
}

thanks.

相關文章