AuthService.php 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. <?php
  2. /**
  3. * 认证服务.
  4. *
  5. * @author nj <nj@gmail.com>
  6. * @date 2020-01-22 11:36:11
  7. */
  8. declare(strict_types=1);
  9. namespace Modules\Api\Services;
  10. use App\Constants\CommonConstant;
  11. use App\Exception\ApiException;
  12. use App\Repositories\Utils\JwtRepository;
  13. use Psr\SimpleCache\CacheInterface;
  14. class AuthService
  15. {
  16. /**
  17. * Jwt受众.
  18. *
  19. * @var string
  20. */
  21. private $jwtAud = 'app-users';
  22. /**
  23. * 获取存储用户设备Token的缓存Key.
  24. * @param string $deviceNo 设备编号
  25. * @param string $deviceType 设备类型
  26. * @return string
  27. */
  28. public function getUserDeviceCacheKey($deviceNo, $deviceType)
  29. {
  30. $cacheKey = 'user_auth_device:'. $deviceNo . '_' . $deviceType;
  31. return $cacheKey;
  32. }
  33. /**
  34. * 创建单点Jwt.
  35. * @param string $userId 用户ID(邀请码)
  36. * @param string $deviceNo 设备编号
  37. * @param string $deviceType 设备类型
  38. * @param string $version 版本
  39. * @param string $fingerHash 指纹
  40. * @return array
  41. * @throws \Psr\SimpleCache\InvalidArgumentException
  42. */
  43. public function createSingleJwt($userId, $deviceNo, $deviceType, $version, $fingerHash = '')
  44. {
  45. $user = [];
  46. $user['user_id'] = $userId;
  47. $user['device_no'] = $deviceNo;
  48. $user['device_type'] = $deviceType;
  49. $user['version'] = $version;
  50. $user['finger_hash'] = $fingerHash;
  51. $jwtRepository = make(JwtRepository::class);
  52. $tokenInfo = $jwtRepository->createAppJwt($user, $this->jwtAud);
  53. $token = $tokenInfo['token'];
  54. $cacheKey = $this->getUserDeviceCacheKey($deviceNo, $deviceType);
  55. $cache = make(CacheInterface::class);
  56. // $cacheToken = $cache->has($cacheKey) ? $cache->get($cacheKey) : '';
  57. // if (!empty($cacheToken)) {
  58. // $cache->delete($cacheKey);
  59. // }
  60. $cache->set($cacheKey, $token, config('jwt.ttl') * 60);
  61. return $tokenInfo;
  62. }
  63. /**
  64. * 获取头部Token.
  65. * @return mixed
  66. */
  67. public function getHeaderToken()
  68. {
  69. return request()->header(CommonConstant::X_TOKEN_NAME, null);
  70. }
  71. /**
  72. * 加密X-TOKEN头部信息.
  73. * @param array $info
  74. * @return false|string
  75. */
  76. public function encodeHeaderTokenInfo(array $info)
  77. {
  78. $token = data_get($info, 'token', '');
  79. $deviceNo = data_get($info, 'device_no', '');
  80. $deviceType = data_get($info, 'device_type', '');
  81. $fingerHash = data_get($info, 'finger_hash', '');
  82. $arrData = [
  83. 'token' => $token,
  84. 'device_no' => $deviceNo,
  85. 'device_type' => $deviceType,
  86. 'finger_hash' => $fingerHash,
  87. ];
  88. $handshake = CommonConstant::getHandShake();
  89. if (!empty($handshake)) {
  90. $arrMap = CommonConstant::getHandSnakeKey($handshake);
  91. $data = hand_encrypt($arrData, $arrMap['key']);
  92. } else {
  93. $data = json_encode($arrData, JSON_UNESCAPED_UNICODE);
  94. }
  95. return $data;
  96. }
  97. /**
  98. * 解密头部X-Token信息.
  99. * @param string $enStr
  100. * @return array|mixed
  101. */
  102. public function decodeHeaderTokenInfo($enStr)
  103. {
  104. $data = [];
  105. $isValidMg = false;
  106. if (class_exists('\Modules\Manage\Services\AuthService')) {
  107. $service = make(\Modules\Manage\Services\AuthService::class);
  108. // 如果有效后台header,则直接不加密,进行明文通讯.
  109. $isValidMg = $service->checkValidMgHeaderHandShake();
  110. }
  111. // 先拿系统里当前flag.
  112. $handshake = CommonConstant::getHandShake();
  113. if (!$isValidMg) {
  114. if (!empty($handshake)) {
  115. $inputData = request()->all();
  116. $inputHandShake = $inputData['handshake'] ?? $handshake;
  117. $handshake = $inputHandShake;
  118. $originData = $enStr;
  119. $arrMap = CommonConstant::getHandSnakeKey($handshake);
  120. if (!is_string($originData)) {
  121. throw new ApiException('数据格式有误3');
  122. }
  123. try {
  124. $data = json_decode(hand_decrypt($originData, $arrMap['key'], ''), true);
  125. } catch (\Throwable $exception) {
  126. throw new ApiException('数据格式有误4');
  127. }
  128. } else {
  129. $data = [];
  130. if (!empty($enStr) && is_string($enStr)) {
  131. $data = json_decode($enStr, true);
  132. }
  133. }
  134. } else {
  135. // TODO 为了满足android在postmain里拿到解密的数据,兼容header是加密的情况.
  136. if (!empty($enStr)) {
  137. if (substr($enStr, 0, 1) == '{') {
  138. $data = json_decode($enStr, true);
  139. } else {
  140. $arrMap = CommonConstant::getHandSnakeKey($handshake);
  141. $data = json_decode(hand_decrypt($enStr, $arrMap['key'], ''), true);
  142. }
  143. }
  144. }
  145. return $data;
  146. }
  147. /**
  148. * 获取Token中的UserId
  149. * @return string
  150. */
  151. public function getUserId()
  152. {
  153. $user_id = '';
  154. $enToken = $this->getHeaderToken();
  155. $arrTokenInfo = $this->decodeHeaderTokenInfo($enToken);
  156. $token = strval(data_get($arrTokenInfo, 'token', ''));
  157. if (!empty($token)) {
  158. $jwtRepository = make(JwtRepository::class);
  159. $validateResult = $jwtRepository->validateToken($token, $this->jwtAud);
  160. if ($validateResult['is_valid']) {
  161. $user_id = $validateResult['token_obj']->claims()->get('user_id');
  162. }
  163. }
  164. return $user_id; //是用户邀请码,非用户id(安全设计)
  165. }
  166. /**
  167. * 从Token中获取用户信息.
  168. * @return array ['user_id', 'device_no', 'device_type']
  169. */
  170. public function getTokenUserInfo() : array
  171. {
  172. $userId = $deviceNo = $deviceType = '';
  173. $enToken = $this->getHeaderToken();
  174. $arrTokenInfo = $this->decodeHeaderTokenInfo($enToken);
  175. $token = strval(data_get($arrTokenInfo, 'token', ''));
  176. if (!empty($token)) {
  177. $jwtRepository = make(JwtRepository::class);
  178. $validateResult = $jwtRepository->validateToken($token, $this->jwtAud);
  179. if ($validateResult['is_valid']) {
  180. $userId = $validateResult['token_obj']->claims()->get('user_id');
  181. $deviceNo = $validateResult['token_obj']->claims()->get('device_no');
  182. $deviceType = $validateResult['token_obj']->claims()->get('device_type');
  183. }
  184. }
  185. $data = [
  186. 'user_id' => $userId, //是用户邀请码,非用户id(安全设计)
  187. 'device_no' => $deviceNo,
  188. 'device_type' => $deviceType,
  189. ];
  190. return $data;
  191. }
  192. }