| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  | <?php | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | namespace app\service; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | use DateTimeImmutable; | 
					
						
							|  |  |  | use DateTimeZone; | 
					
						
							|  |  |  | use Exception; | 
					
						
							|  |  |  | use Lcobucci\Clock\SystemClock; | 
					
						
							|  |  |  | use Lcobucci\JWT\Configuration; | 
					
						
							|  |  |  | use Lcobucci\JWT\Signer\Hmac\Sha256; | 
					
						
							|  |  |  | use Lcobucci\JWT\Signer\Key\InMemory; | 
					
						
							|  |  |  | use Lcobucci\JWT\UnencryptedToken; | 
					
						
							|  |  |  | use Lcobucci\JWT\Validation\Constraint\IssuedBy; | 
					
						
							|  |  |  | use Lcobucci\JWT\Validation\Constraint\LooseValidAt; | 
					
						
							|  |  |  | use Lcobucci\JWT\Validation\Constraint\PermittedFor; | 
					
						
							|  |  |  | use Lcobucci\JWT\Validation\Constraint\ValidAt; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | class Jwt | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  |     private static $secret = 'lF9XkOMfpsR0ODVfbasY2HtDrIps8GIX'; | 
					
						
							| 
									
										
										
										
											2022-06-10 14:10:21 +08:00
										 |  |  |     private static $expire = 86400 * 3;//秒
 | 
					
						
							| 
									
										
										
										
											2022-05-25 19:35:57 +08:00
										 |  |  |     private static $iss = 'dxtc';//jwt签发者
 | 
					
						
							|  |  |  |     private static $sub = 'dxtc-customer';//jwt所面向的用户
 | 
					
						
							|  |  |  |     private static $aud = 'dxtc-customer';//接受jwt的一方
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     private static function config(): Configuration | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return Configuration::forSymmetricSigner( | 
					
						
							|  |  |  |         // You may use any HMAC variations (256, 384, and 512)
 | 
					
						
							|  |  |  |             new Sha256(), | 
					
						
							|  |  |  |             // replace the value below with a key of your own!
 | 
					
						
							|  |  |  |             InMemory::base64Encoded(self::$secret) | 
					
						
							|  |  |  |         // You may also override the JOSE encoder/decoder if needed by providing extra arguments here
 | 
					
						
							|  |  |  |         ); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * 获取token有效期 单位秒 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @return int | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function expire(): int | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         return self::$expire; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * 编码 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param $data | 
					
						
							|  |  |  |      * @param  int  $expire | 
					
						
							|  |  |  |      * @return string | 
					
						
							|  |  |  |      * @throws Exception | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function generate($data, int $expire = 0): string | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $expire = $expire <= 0 ? self::$expire : $expire; | 
					
						
							|  |  |  |         $now = new DateTimeImmutable('now', new DateTimeZone('Asia/ShangHai')); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         $token = self::config()->builder() | 
					
						
							|  |  |  |             // Configures the issuer (iss claim)
 | 
					
						
							|  |  |  |             ->issuedBy(self::$iss) | 
					
						
							|  |  |  |             // Configures the audience (aud claim)
 | 
					
						
							|  |  |  |             ->permittedFor(self::$aud) | 
					
						
							|  |  |  |             // Configures the id (jti claim)
 | 
					
						
							|  |  |  |             //            ->identifiedBy($this->jti)
 | 
					
						
							|  |  |  |             // Configures the time that the token was issue (iat claim)
 | 
					
						
							|  |  |  |             ->issuedAt($now) | 
					
						
							|  |  |  |             // Configures the expiration time of the token (exp claim)
 | 
					
						
							|  |  |  |             ->expiresAt($now->modify(sprintf('+%d seconds', $expire))) | 
					
						
							|  |  |  |             // Configures a new claim, called "uid"
 | 
					
						
							|  |  |  |             ->withClaim('data', $data) | 
					
						
							|  |  |  |             // Configures a new header, called "foo"
 | 
					
						
							|  |  |  |             //            ->withHeader('foo', 'bar')
 | 
					
						
							|  |  |  |             // Builds a new token
 | 
					
						
							|  |  |  |             ->getToken(self::config()->signer(), self::config()->signingKey()); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         return $token->toString(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * 解析 | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param  string  $tokenStr | 
					
						
							|  |  |  |      * @return array|mixed | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function parse(string $tokenStr) | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $config = self::config(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             $token = $config->parser()->parse($tokenStr); | 
					
						
							|  |  |  |             assert($token instanceof UnencryptedToken); | 
					
						
							|  |  |  |             return $token->claims()->all()['data'] ?? []; | 
					
						
							|  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |             return []; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     /** | 
					
						
							|  |  |  |      * 验证token | 
					
						
							|  |  |  |      * | 
					
						
							|  |  |  |      * @param  string  $tokenStr | 
					
						
							|  |  |  |      * @return bool | 
					
						
							|  |  |  |      */ | 
					
						
							|  |  |  |     public static function validate(string $tokenStr): bool | 
					
						
							|  |  |  |     { | 
					
						
							|  |  |  |         $config = self::config(); | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |             $token = $config->parser()->parse($tokenStr); | 
					
						
							|  |  |  |             assert($token instanceof UnencryptedToken); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             //验证签发人iss是否正确
 | 
					
						
							|  |  |  |             $validateIssued = new IssuedBy(self::$iss); | 
					
						
							|  |  |  |             $config->setValidationConstraints($validateIssued); | 
					
						
							|  |  |  |             //验证客户端aud是否匹配
 | 
					
						
							|  |  |  |             $validateAud = new PermittedFor(self::$aud); | 
					
						
							|  |  |  |             $config->setValidationConstraints($validateAud); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             //验证是否过期 exp
 | 
					
						
							|  |  |  |             $timezone        = new DateTimeZone('Asia/Shanghai'); | 
					
						
							|  |  |  |             $now             = new SystemClock($timezone); | 
					
						
							|  |  |  |             $validateExpired = new LooseValidAt($now); | 
					
						
							|  |  |  |             $config->setValidationConstraints($validateExpired); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             $constraints = $config->validationConstraints(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |             return $config->validator()->validate($token, ...$constraints); | 
					
						
							|  |  |  |         } catch (Exception $e) { | 
					
						
							|  |  |  |             return false; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | } |