From 68ecac2fb97d199df2580db05ac84ca9c3411a6c Mon Sep 17 00:00:00 2001 From: ctexthuang Date: Fri, 12 Sep 2025 23:54:03 +0800 Subject: [PATCH] fix : jwt --- app/Controller/Admin/LoginController.php | 9 ++- app/Exception/ErrException.php | 19 ++++++ .../Handler/BaseErrExceptionHandler.php | 2 +- app/Exception/Handler/JwtExceptionHandler.php | 8 ++- app/Lib/Jwt/AbstractJwt.php | 68 +++++++++++-------- app/Middleware/Token/AdminTokenMiddleware.php | 4 +- app/Service/Admin/Login/RefreshService.php | 27 ++++++++ app/Service/BaseTokenService.php | 26 ++++--- 8 files changed, 121 insertions(+), 42 deletions(-) create mode 100644 app/Service/Admin/Login/RefreshService.php diff --git a/app/Controller/Admin/LoginController.php b/app/Controller/Admin/LoginController.php index 73c9524..79ba501 100644 --- a/app/Controller/Admin/LoginController.php +++ b/app/Controller/Admin/LoginController.php @@ -8,6 +8,7 @@ use App\Annotation\ResponseFormat; use App\Controller\AbstractController; use App\Request\Admin\LoginRequest; use App\Service\Admin\Login\LoginService; +use App\Service\Admin\Login\RefreshService; use Hyperf\HttpServer\Annotation\Controller; use Hyperf\HttpServer\Annotation\RequestMapping; use Hyperf\Validation\Annotation\Scene; @@ -18,8 +19,14 @@ final class LoginController extends AbstractController { #[RequestMapping(path: "login", methods: "POST")] #[Scene(scene: "login")] - public function login(LoginRequest $request) + public function login(LoginRequest $request): array { return (new LoginService)->handle(); } + + #[RequestMapping(path: "refresh", methods: "POST")] + public function refresh(): array + { + return (new RefreshService)->handle(); + } } diff --git a/app/Exception/ErrException.php b/app/Exception/ErrException.php index 0da91cb..26ee36e 100644 --- a/app/Exception/ErrException.php +++ b/app/Exception/ErrException.php @@ -11,4 +11,23 @@ class ErrException extends ServerException * @var int */ protected $code = ResultCode::ERROR; + + /** + * @var array + */ + protected array $data = []; + + public function __construct(string $message = "", int $code = 0, array $data = [], ?Throwable $previous = null) + { + parent::__construct($message, $code, $previous); + $this->data = $data; + } + + /** + * @return array + */ + public function getData(): array + { + return $this->data; + } } \ No newline at end of file diff --git a/app/Exception/Handler/BaseErrExceptionHandler.php b/app/Exception/Handler/BaseErrExceptionHandler.php index 1e4c291..62cbf1b 100644 --- a/app/Exception/Handler/BaseErrExceptionHandler.php +++ b/app/Exception/Handler/BaseErrExceptionHandler.php @@ -49,7 +49,7 @@ abstract class BaseErrExceptionHandler extends ExceptionHandler * @var AdminReturn|ApiReturn $returnObj */ $returnObj = $this->container->get($returnClass); - $result = $returnObj->error($e->getMessage(), $e->getCode()); + $result = $returnObj->error($e->getMessage(), $e->getCode(), $e?->getData() ?? []); $this->stopPropagation(); return $response->withHeader("Content-Type", "application/json") ->withStatus(200) diff --git a/app/Exception/Handler/JwtExceptionHandler.php b/app/Exception/Handler/JwtExceptionHandler.php index 921f0d7..6aaf3d6 100644 --- a/app/Exception/Handler/JwtExceptionHandler.php +++ b/app/Exception/Handler/JwtExceptionHandler.php @@ -31,7 +31,11 @@ class JwtExceptionHandler extends BaseErrExceptionHandler return $response; } - protected function modifyException(JWTException $e): Throwable + /** + * @param JWTException $e + * @return ErrException + */ + protected function modifyException(JWTException $e): ErrException { // 根据不同的异常类型设置不同的code和message switch ($e->getMessage()) { @@ -51,7 +55,7 @@ class JwtExceptionHandler extends BaseErrExceptionHandler $e->setCustomMessage($message); } - return $e; + return New ErrException($message,$code); } /** diff --git a/app/Lib/Jwt/AbstractJwt.php b/app/Lib/Jwt/AbstractJwt.php index cc5a4a6..aee0eaa 100644 --- a/app/Lib/Jwt/AbstractJwt.php +++ b/app/Lib/Jwt/AbstractJwt.php @@ -2,6 +2,8 @@ namespace App\Lib\Jwt; +use App\Constants\ResultCode; +use App\Exception\ErrException; use App\Interface\JwtInterface; use Carbon\Carbon; use Hyperf\Cache\CacheManager; @@ -16,6 +18,7 @@ use Lcobucci\JWT\UnencryptedToken; use Lcobucci\JWT\Validation\Constraint; use Lcobucci\JWT\Validation\Constraint\SignedWith; use Lcobucci\JWT\Validation\Constraint\StrictValidAt; +use Lcobucci\JWT\Validation\RequiredConstraintsViolated; use Psr\SimpleCache\InvalidArgumentException; abstract class AbstractJwt implements JwtInterface @@ -85,21 +88,24 @@ abstract class AbstractJwt implements JwtInterface */ public function parserAccessToken(string $accessToken): UnencryptedToken { - echo 1; - 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 - ); + try { + 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 + ); + } catch (RequiredConstraintsViolated $e) { + throw new ErrException('token过期',ResultCode::JWT_EXPIRED,['err_msg' => $e->getMessage()]); + } } /** @@ -108,20 +114,24 @@ abstract class AbstractJwt implements JwtInterface */ 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 - ); + try { + 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 + ); + }catch (RequiredConstraintsViolated $e) { + throw new ErrException('refresh_token过期',ResultCode::JWT_EXPIRED,['err_msg' => $e->getMessage()]); + } } /** diff --git a/app/Middleware/Token/AdminTokenMiddleware.php b/app/Middleware/Token/AdminTokenMiddleware.php index 156189f..bb645c6 100644 --- a/app/Middleware/Token/AdminTokenMiddleware.php +++ b/app/Middleware/Token/AdminTokenMiddleware.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace App\Middleware\Token; +use App\Constants\ResultCode; use App\Exception\ErrException; use App\Interface\JwtInterface; use Lcobucci\JWT\Token\RegisteredClaims; @@ -24,6 +25,7 @@ final class AdminTokenMiddleware extends AbstractTokenMiddleware public function checkIssuer(UnencryptedToken $token): void { $audience = $token->claims()->get(RegisteredClaims::ISSUER); - if ($audience === env('APP_NAME') .'_admin') throw new ErrException('token错误'); + + if ($audience !== env('APP_NAME') .'_admin') throw new ErrException('token错误',ResultCode::JWT_ERROR); } } diff --git a/app/Service/Admin/Login/RefreshService.php b/app/Service/Admin/Login/RefreshService.php new file mode 100644 index 0000000..6c4fa09 --- /dev/null +++ b/app/Service/Admin/Login/RefreshService.php @@ -0,0 +1,27 @@ +adminReturn->success(); + } + + public function refreshToken(UnencryptedToken $token) + { + + } +} \ No newline at end of file diff --git a/app/Service/BaseTokenService.php b/app/Service/BaseTokenService.php index 1b16f08..0c3e9d6 100644 --- a/app/Service/BaseTokenService.php +++ b/app/Service/BaseTokenService.php @@ -14,8 +14,10 @@ use App\Exception\ErrException; use App\Interface\CheckTokenInterface; use App\Lib\Jwt\JwtFactory; use Hyperf\Di\Annotation\Inject; +use Lcobucci\JWT\Token\RegisteredClaims; use Lcobucci\JWT\UnencryptedToken; use App\Interface\JwtInterface; +use function Hyperf\Support\value; final class BaseTokenService implements CheckTokenInterface { @@ -35,14 +37,6 @@ final class BaseTokenService implements CheckTokenInterface return $this->jwtFactory->get($this->jwt); } - /** - * @return JwtInterface - */ - public function getApiJwt(): JwtInterface - { - return $this->jwtFactory->get('api'); - } - /** * @param UnencryptedToken $token * @return void @@ -51,4 +45,20 @@ final class BaseTokenService implements CheckTokenInterface { $this->getJwt()->hasBlackList($token) && throw new ErrException('token已过期'); } + + /** + * @param UnencryptedToken $token + * @return \Closure + */ + public function refreshToken(UnencryptedToken $token): \Closure + { + return value(static function (JwtInterface $jwt) use ($token) { + $jwt->addBlackList($token); + return [ + 'access_token' => $jwt->builderAccessToken($token->claims()->get(RegisteredClaims::ID))->toString(), + 'refresh_token' => $jwt->builderRefreshToken($token->claims()->get(RegisteredClaims::ID))->toString(), + 'expire_at' => (int) $jwt->getConfig('ttl', 0), + ]; + }, $this->getJwt()); + } } \ No newline at end of file