Token.php 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | A3Mall
  4. // +----------------------------------------------------------------------
  5. // | Copyright (c) 2020 http://www.a3-mall.com All rights reserved.
  6. // +----------------------------------------------------------------------
  7. // | Author: xzncit <158373108@qq.com>
  8. // +----------------------------------------------------------------------
  9. namespace mall\library\tools\jwt;
  10. use DateTimeImmutable;
  11. use DateTimeZone;
  12. use Lcobucci\Clock\SystemClock;
  13. use Lcobucci\JWT\Token\Plain;
  14. use Lcobucci\JWT\Validation\Constraint\IdentifiedBy;
  15. use Lcobucci\JWT\Validation\Constraint\IssuedBy;
  16. use Lcobucci\JWT\Validation\Constraint\PermittedFor;
  17. use Lcobucci\JWT\Validation\Constraint\ValidAt;
  18. use Lcobucci\JWT\Validation\RequiredConstraintsViolated;
  19. use Lcobucci\JWT\Validation\Constraint\SignedWith;
  20. use think\facade\Request;
  21. class Token {
  22. /**
  23. * 生成token
  24. * @param string $name
  25. * @param string $value
  26. * @param array $options
  27. * @return string
  28. */
  29. public static function get($name,$value,$options=[]){
  30. $config = Config::get();
  31. $now = new DateTimeImmutable();
  32. $time = time();
  33. $builder = $config->builder()
  34. ->issuedBy(env("website.app_web_url"))
  35. ->permittedFor(env("website.app_web_url"))
  36. ->identifiedBy(env('jwt.sign'))
  37. ->issuedAt($now)
  38. ->canOnlyBeUsedAfter($now->modify('-1 second'))
  39. ->expiresAt($now->modify('+15 day'))
  40. ->withClaim($name, str_replace("=", "", base64_encode(implode("|",[$value,$time,md5(env('jwt.sign') . $value . $time)]))));
  41. if(!empty($options)){
  42. $builder->withHeader($options["name"], $options["value"]);
  43. }
  44. return (string)$builder->getToken($config->signer(), $config->signingKey());
  45. }
  46. public static function check($token=""){
  47. $token = empty($token) ? Request::header("Auth-Token") : $token;
  48. $value = trim(ltrim($token, 'Bearer'));
  49. if(empty($value)){
  50. throw new \Exception("您还未登录,请登录",401);
  51. }
  52. if(self::verify($value)){
  53. return $value;
  54. }
  55. }
  56. /**
  57. * 检测
  58. * @param string $data
  59. * @return bool
  60. */
  61. public static function verify($data){
  62. $config = Config::get();
  63. $token = $config->parser()->parse($data);
  64. if(!($token instanceof Plain)){
  65. throw new \Exception("验证token未通过",401);
  66. }
  67. // 验证是否过期
  68. $claims = $token->claims();
  69. $jti = (string)$claims->get('jti');
  70. $iss = (string)$claims->get('iss');
  71. //$aud = $claims->get('aud');
  72. $nbf = $claims->get('nbf');
  73. $exp = $claims->get('exp');
  74. $now = new \DateTimeImmutable();
  75. // 未分配
  76. if($nbf > $now) {
  77. throw new \Exception("token还未生效",4001);
  78. }
  79. // 已过期
  80. if($exp < $now) {
  81. throw new \Exception("token已过期",401);
  82. }
  83. $timezone = new DateTimeZone('Asia/Shanghai');
  84. $now = new SystemClock($timezone);
  85. $validateAt = new ValidAt($now);
  86. //验证jwt id是否匹配
  87. $validationIdentifiedBy = new IdentifiedBy($jti);
  88. // 验证签发人url是否正确
  89. $validationIssuedBy = new IssuedBy($iss);
  90. $validationSignedWith = new SignedWith($config->signer(),$config->signingKey());
  91. $config->setValidationConstraints(
  92. $validateAt,$validationIdentifiedBy,$validationIssuedBy,$validationSignedWith
  93. );
  94. $constraints = $config->validationConstraints();
  95. try {
  96. $config->validator()->assert($token, ...$constraints);
  97. return true;
  98. } catch (RequiredConstraintsViolated $e) {
  99. throw new \Exception($e->getMessage(),401);
  100. }
  101. }
  102. /**
  103. * 解析
  104. * @param string $data
  105. * @param string $field
  106. * @return false|\Lcobucci\JWT\Token\DataSet
  107. */
  108. public static function parse($data,$field=""){
  109. $config = Config::get();
  110. $token = $config->parser()->parse($data);
  111. if(!($token instanceof Plain)){
  112. return false;
  113. }
  114. if(empty($field)){
  115. return $token->claims();
  116. }
  117. $value = $token->claims()->get($field);
  118. return self::parseData($value);
  119. }
  120. public static function parseData($value){
  121. $string = base64_decode($value);
  122. $arr = explode('|', $string);
  123. if (count($arr) != 3) {
  124. return 1;
  125. }
  126. list($value,$time,$md5) = $arr;
  127. if(md5(env('jwt.sign').$value.$time) == $md5){
  128. return ["value"=>$value,"time"=>$time];
  129. }
  130. return 2;
  131. }
  132. }