Redis.php 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. <?php
  2. namespace app\common\library\token\driver;
  3. use app\common\library\token\Driver;
  4. /**
  5. * Token操作类
  6. */
  7. class Redis extends Driver
  8. {
  9. protected $options = [
  10. 'host' => '127.0.0.1',
  11. 'port' => 6379,
  12. 'password' => '',
  13. 'select' => 0,
  14. 'timeout' => 0,
  15. 'expire' => 0,
  16. 'persistent' => false,
  17. 'userprefix' => 'up:',
  18. 'tokenprefix' => 'tp:',
  19. ];
  20. /**
  21. * 构造函数
  22. * @param array $options 缓存参数
  23. * @throws \BadFunctionCallException
  24. * @access public
  25. */
  26. public function __construct($options = [])
  27. {
  28. $redis_config = config('redis');
  29. $this->options['host'] = $redis_config['host'];
  30. $this->options['port'] = $redis_config['port'];
  31. $this->options['password'] = $redis_config['password'];
  32. $this->options['select'] = $redis_config['select'];
  33. if (!extension_loaded('redis')) {
  34. throw new \BadFunctionCallException('not support: redis');
  35. }
  36. if (!empty($options)) {
  37. $this->options = array_merge($this->options, $options);
  38. }
  39. $this->handler = new \Redis;
  40. if ($this->options['persistent']) {
  41. $this->handler->pconnect($this->options['host'], $this->options['port'], $this->options['timeout'], 'persistent_id_' . $this->options['select']);
  42. } else {
  43. $this->handler->connect($this->options['host'], $this->options['port'], $this->options['timeout']);
  44. }
  45. if ('' != $this->options['password']) {
  46. $this->handler->auth($this->options['password']);
  47. }
  48. if (0 != $this->options['select']) {
  49. $this->handler->select($this->options['select']);
  50. }
  51. }
  52. /**
  53. * 获取加密后的Token
  54. * @param string $token Token标识
  55. * @return string
  56. */
  57. protected function getEncryptedToken($token)
  58. {
  59. $config = \think\Config::get('token');
  60. $token = $token ?? ''; // 为兼容 php8
  61. return $this->options['tokenprefix'] . hash_hmac($config['hashalgo'], $token, $config['key']);
  62. }
  63. /**
  64. * 获取会员的key
  65. * @param $user_id
  66. * @return string
  67. */
  68. protected function getUserKey($user_id)
  69. {
  70. return $this->options['userprefix'] . $user_id;
  71. }
  72. /**
  73. * 存储Token
  74. * @param string $token Token
  75. * @param int $user_id 会员ID
  76. * @param int $expire 过期时长,0表示无限,单位秒
  77. * @return bool
  78. */
  79. public function set($token, $user_id, $expire = 0)
  80. {
  81. if (is_null($expire)) {
  82. $expire = $this->options['expire'];
  83. }
  84. if ($expire instanceof \DateTime) {
  85. $expire = $expire->getTimestamp() - time();
  86. }
  87. $key = $this->getEncryptedToken($token);
  88. if ($expire) {
  89. $result = $this->handler->setex($key, $expire, $user_id);
  90. } else {
  91. $result = $this->handler->set($key, $user_id);
  92. }
  93. //写入会员关联的token
  94. $this->handler->sAdd($this->getUserKey($user_id), $key);
  95. return $result;
  96. }
  97. /**
  98. * 获取Token内的信息
  99. * @param string $token
  100. * @return array
  101. */
  102. public function get($token)
  103. {
  104. //方便测试
  105. if(strpos($token,'testuid_') !== false && config('api_exception') === true){
  106. $uid = substr($token,8);
  107. return [
  108. 'user_id' => intval($uid),
  109. ];
  110. }
  111. //方便测试
  112. $key = $this->getEncryptedToken($token);
  113. $value = $this->handler->get($key);
  114. if (is_null($value) || false === $value) {
  115. return [];
  116. }
  117. //获取有效期
  118. $expire = $this->handler->ttl($key);
  119. $expire = $expire < 0 ? 365 * 86400 : $expire;
  120. $expiretime = time() + $expire;
  121. //解决使用redis方式储存token时api接口Token刷新与检测因expires_in拼写错误报错的BUG
  122. $result = ['token' => $token, 'user_id' => $value, 'expiretime' => $expiretime, 'expires_in' => $expire];
  123. return $result;
  124. }
  125. /**
  126. * 判断Token是否可用
  127. * @param string $token Token
  128. * @param int $user_id 会员ID
  129. * @return boolean
  130. */
  131. public function check($token, $user_id)
  132. {
  133. $data = self::get($token);
  134. return $data && $data['user_id'] == $user_id ? true : false;
  135. }
  136. /**
  137. * 删除Token
  138. * @param string $token
  139. * @return boolean
  140. */
  141. public function delete($token)
  142. {
  143. $data = $this->get($token);
  144. if ($data) {
  145. $key = $this->getEncryptedToken($token);
  146. $user_id = $data['user_id'];
  147. $this->handler->del($key);
  148. $this->handler->sRem($this->getUserKey($user_id), $key);
  149. }
  150. return true;
  151. }
  152. /**
  153. * 删除指定用户的所有Token
  154. * @param int $user_id
  155. * @return boolean
  156. */
  157. public function clear($user_id)
  158. {
  159. $keys = $this->handler->sMembers($this->getUserKey($user_id));
  160. $this->handler->del($this->getUserKey($user_id));
  161. $this->handler->del($keys);
  162. return true;
  163. }
  164. }