mirror of
https://gitee.com/ctexthuang/hyperf_rbac_framework_server_ctexthuang.git
synced 2025-12-25 23:57:49 +08:00
237 lines
6.8 KiB
PHP
237 lines
6.8 KiB
PHP
<?php
|
|
|
|
namespace App\Lib\Jwt;
|
|
|
|
use App\Common\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\Token\RegisteredClaims;
|
|
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)
|
|
->issuedBy($this->getConfig('claims.'.RegisteredClaims::ISSUER,''));
|
|
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)
|
|
->issuedBy($this->getConfig('claims.'.RegisteredClaims::ISSUER,''))
|
|
->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();
|
|
}
|
|
} |