first commit

This commit is contained in:
2025-09-12 15:23:08 +08:00
commit a80c237bbb
117 changed files with 15628 additions and 0 deletions

233
app/Lib/Jwt/AbstractJwt.php Normal file
View File

@@ -0,0 +1,233 @@
<?php
namespace App\Lib\Jwt;
use App\Interface\JwtInterface;
use Carbon\Carbon;
use Hyperf\Cache\CacheManager;
use Hyperf\Cache\Driver\DriverInterface;
use Hyperf\Collection\Arr;
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\JwtFacade;
use Lcobucci\JWT\Signer;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\UnencryptedToken;
use Lcobucci\JWT\Validation\Constraint;
use Lcobucci\JWT\Validation\Constraint\SignedWith;
use Lcobucci\JWT\Validation\Constraint\StrictValidAt;
use Psr\SimpleCache\InvalidArgumentException;
abstract class AbstractJwt implements JwtInterface
{
/**
* @param array $config
* @param CacheManager $cacheManager
* @param Clock $clock
* @param AccessTokenConstraint $accessTokenConstraint
* @param RefreshTokenConstraint $refreshTokenConstraint
*/
public function __construct(
private readonly array $config,
private readonly CacheManager $cacheManager,
private readonly Clock $clock,
private readonly AccessTokenConstraint $accessTokenConstraint,
private readonly RefreshTokenConstraint $refreshTokenConstraint
) {}
/**
* @param string $sub
* @param \Closure|null $callable
* @return UnencryptedToken
*/
public function builderAccessToken(string $sub, ?\Closure $callable = null): UnencryptedToken
{
return $this->getJwtFacade()->issue(
$this->getSigner(),
$this->getSigningKey(),
function (Builder $builder, \DateTimeImmutable $immutable) use ($sub, $callable) {
$builder = $builder->identifiedBy($sub);
if ($callable !== null) {
$builder = $callable($builder);
}
return $builder->expiresAt($this->getExpireAt($immutable));
}
);
}
/**
* @param string $sub
* @param \Closure|null $callable
* @return UnencryptedToken
*/
public function builderRefreshToken(string $sub, ?\Closure $callable = null): UnencryptedToken
{
return $this->getJwtFacade()->issue(
$this->getSigner(),
$this->getSigningKey(),
function (Builder $builder, \DateTimeImmutable $immutable) use ($sub, $callable) {
$builder = $builder->identifiedBy($sub);
$builder = $builder->expiresAt($this->getRefreshExpireAt($immutable));
if ($callable !== null) {
$builder = $callable($builder);
}
return $builder->relatedTo('refresh');
}
);
}
/**
* @param string $accessToken
* @return UnencryptedToken
*/
public function parserAccessToken(string $accessToken): UnencryptedToken
{
return $this->getJwtFacade()
->parse(
$accessToken,
new SignedWith(
$this->getSigner(),
$this->getSigningKey()
),
new StrictValidAt(
$this->clock,
$this->clock->now()->diff($this->getExpireAt($this->clock->now()))
),
$this->getBlackListConstraint(),
$this->refreshTokenConstraint
);
}
/**
* @param string $refreshToken
* @return UnencryptedToken
*/
public function parserRefreshToken(string $refreshToken): UnencryptedToken
{
return $this->getJwtFacade()
->parse(
$refreshToken,
new SignedWith(
$this->getSigner(),
$this->getSigningKey()
),
new StrictValidAt(
$this->clock,
$this->clock->now()->diff($this->getRefreshExpireAt($this->clock->now()))
),
$this->getBlackListConstraint(),
$this->accessTokenConstraint
);
}
/**
* @param UnencryptedToken $token
* @return bool
* @throws InvalidArgumentException
*/
public function addBlackList(UnencryptedToken $token): bool
{
return $this->getCacheDriver()->set($token->toString(), 1, $this->getBlackConfig('ttl', 600));
}
/**
* @param UnencryptedToken $token
* @return bool
* @throws InvalidArgumentException
*/
public function hasBlackList(UnencryptedToken $token): bool
{
return $this->getCacheDriver()->has($token->toString());
}
/**
* @param UnencryptedToken $token
* @return bool
* @throws InvalidArgumentException
*/
public function removeBlackList(UnencryptedToken $token): bool
{
return $this->getCacheDriver()->delete($token->toString());
}
/**
* @param string $key
* @param mixed|null $default
* @return mixed
*/
public function getConfig(string $key, mixed $default = null): mixed
{
return Arr::get($this->config, $key, $default);
}
/**
* @return JwtFacade
*/
private function getJwtFacade(): JwtFacade
{
return new JwtFacade(clock: $this->clock);
}
/**
* @return Signer
*/
private function getSigner(): Signer
{
return Arr::get($this->config, 'alg');
}
/**
* @return Key
*/
private function getSigningKey(): Key
{
return Arr::get($this->config, 'key');
}
/**
* @return DriverInterface
*/
private function getCacheDriver(): DriverInterface
{
return $this->cacheManager->getDriver($this->getBlackConfig('connection'));
}
/**
* @param string $name
* @param mixed|null $default
* @return mixed
*/
private function getBlackConfig(string $name, mixed $default = null): mixed
{
return Arr::get($this->config, 'blacklist.' . $name, $default);
}
/**
* @return Constraint
*/
private function getBlackListConstraint(): Constraint
{
return new BlackListConstraint((bool) $this->getBlackConfig('enable', false), $this->getCacheDriver());
}
/**
* @param \DateTimeImmutable $immutable
* @return \DateTimeImmutable
*/
private function getExpireAt(\DateTimeImmutable $immutable): \DateTimeImmutable
{
return Carbon::create($immutable)
->addSeconds(Arr::get($this->config, 'ttl', 3600))
->toDateTimeImmutable();
}
/**
* @param \DateTimeImmutable $immutable
* @return \DateTimeImmutable
*/
private function getRefreshExpireAt(\DateTimeImmutable $immutable): \DateTimeImmutable
{
return Carbon::create($immutable)
->addSeconds(Arr::get($this->config, 'refresh_ttl', 7200))
->toDateTimeImmutable();
}
}