phper666 / jwt-auth

能直接在hyperf框架中使用jwt的组件. 用之前,请详细的看下下面的文档~
191 stars 35 forks source link

lcobucci/jwt 3.3 中的 Lcobucci\JWT\Claim\Factory类 。在php7.2 下 存在内存泄漏。其它版本未知 #39

Closed iQiFengLe closed 1 year ago

iQiFengLe commented 3 years ago

Lcobucci\JWT\Claim\Factory 该类的构造方法:

public function __construct(array $callbacks = [])
    {
        $this->callbacks = array_merge(
            [
                'iat' => [$this, 'createLesserOrEqualsTo'],
                'nbf' => [$this, 'createLesserOrEqualsTo'],
                'exp' => [$this, 'createGreaterOrEqualsTo'],
                'iss' => [$this, 'createEqualsTo'],
                'aud' => [$this, 'createEqualsTo'],
                'sub' => [$this, 'createEqualsTo'],
                'jti' => [$this, 'createEqualsTo']
            ],
            $callbacks
        );
    }

由于自己将自己引用了,导致new 出的对象无法释放。 如图: 未覆写 由于自我引用导致 new 一次内存增加一次,且大概率不会释放(偶尔也会释放一次,不过时间很长);

解决方法:继承Lcobucci\JWT\Claim\Factory 类覆写全部方法

use Lcobucci\JWT\Claim\Basic;
use Lcobucci\JWT\Claim\EqualsTo;
use Lcobucci\JWT\Claim\Factory;
use Lcobucci\JWT\Claim\GreaterOrEqualsTo;
use Lcobucci\JWT\Claim\LesserOrEqualsTo;

/**
 * 解决内存泄漏
 * Class LcobucciClaimFactory
 * @package App\JWT
 */
class LcobucciClaimFactory extends Factory {

    protected $callbacks;

    public function __construct(array $callbacks = []){
        $this->callbacks = array_merge(
            [
                'iat' => 'createLesserOrEqualsTo',
                'nbf' => 'createLesserOrEqualsTo',
                'exp' => 'createGreaterOrEqualsTo',
                'iss' => 'createEqualsTo',
                'aud' => 'createEqualsTo',
                'sub' => 'createEqualsTo',
                'jti' => 'createEqualsTo'
            ],
            $callbacks
        );
    }
    public function create($name, $value)
    {
        if (!empty($this->callbacks[$name])) {
            return call_user_func([$this,$this->callbacks[$name]], $name, $value);
        }
        return $this->createBasic($name, $value);
    }
    /**
     * Creates a claim that can be compared (greator or equals)
     *
     * @param string $name
     * @param mixed $value
     *
     * @return GreaterOrEqualsTo
     */
    protected function createGreaterOrEqualsTo($name, $value)
    {
        return new GreaterOrEqualsTo($name, $value);
    }

    /**
     * Creates a claim that can be compared (greator or equals)
     *
     * @param string $name
     * @param mixed $value
     *
     * @return LesserOrEqualsTo
     */
    protected function createLesserOrEqualsTo($name, $value)
    {
        return new LesserOrEqualsTo($name, $value);
    }

    /**
     * Creates a claim that can be compared (equals)
     *
     * @param string $name
     * @param mixed $value
     *
     * @return EqualsTo
     */
    protected function createEqualsTo($name, $value)
    {
        return new EqualsTo($name, $value);
    }

    /**
     * Creates a basic claim
     *
     * @param string $name
     * @param mixed $value
     *
     * @return Basic
     */
    protected function createBasic($name, $value)
    {
        return new Basic($name, $value);
    }

}

修改两个方法

/**
     * 获取生成对象
     * @return Builder
     */
    public function getBuilder(): Builder{
        return new Builder(new Encoder(), new LcobucciClaimFactory());
    }
    /**
     * 获取解析对象
     * @return Parser
     */
    public function getParser(): Parser{
        return new Parser(new Decoder(), new LcobucciClaimFactory());
    }

再次测试

覆写后

teg1c commented 3 years ago

这么严重的问题作者竟然不解决,最好的解决办法就是让 Lcobucci\JWT\Claim\Factory 变成单例

修改 src/Util/JWTUtil.php

declare(strict_types=1);
namespace Phper666\JWTAuth\Util;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Claim\Factory as ClaimFactory;
use Lcobucci\JWT\Parser;
use Lcobucci\JWT\Parsing\Decoder;
use Lcobucci\JWT\Parsing\Encoder;
use Lcobucci\JWT\ValidationData;
use Hyperf\Utils\ApplicationContext;

/**
 * Created by PhpStorm.
 * User: liyuzhao
 * Date: 2020/4/21
 * Time: 1:51 下午
 */
class JWTUtil
{
//....
 public static function getParser(Decoder $decoder = null, ClaimFactory $claimFactory = null)
    {
        empty($claimFactory) && $claimFactory = ApplicationContext::getContainer()->get(ClaimFactory::class);
        return new Parser($decoder, $claimFactory);
    }
//...

ok,解决

phper666 commented 2 years ago

已经支持php8,可以更新到4.0.x版本试试,更新时,请看下redeme