* @date 2020-01-22 11:36:11 */ declare(strict_types=1); namespace Modules\Api\Services; use App\Constants\CommonConstant; use App\Exception\ApiException; use App\Repositories\Utils\JwtRepository; use Psr\SimpleCache\CacheInterface; class AuthService { /** * Jwt受众. * * @var string */ private $jwtAud = 'app-users'; /** * 获取存储用户设备Token的缓存Key. * @param string $deviceNo 设备编号 * @param string $deviceType 设备类型 * @return string */ public function getUserDeviceCacheKey($deviceNo, $deviceType) { $cacheKey = 'user_auth_device:'. $deviceNo . '_' . $deviceType; return $cacheKey; } /** * 创建单点Jwt. * @param string $userId 用户ID(邀请码) * @param string $deviceNo 设备编号 * @param string $deviceType 设备类型 * @param string $version 版本 * @param string $fingerHash 指纹 * @return array * @throws \Psr\SimpleCache\InvalidArgumentException */ public function createSingleJwt($userId, $deviceNo, $deviceType, $version, $fingerHash = '') { $user = []; $user['user_id'] = $userId; $user['device_no'] = $deviceNo; $user['device_type'] = $deviceType; $user['version'] = $version; $user['finger_hash'] = $fingerHash; $jwtRepository = make(JwtRepository::class); $tokenInfo = $jwtRepository->createAppJwt($user, $this->jwtAud); $token = $tokenInfo['token']; $cacheKey = $this->getUserDeviceCacheKey($deviceNo, $deviceType); $cache = make(CacheInterface::class); // $cacheToken = $cache->has($cacheKey) ? $cache->get($cacheKey) : ''; // if (!empty($cacheToken)) { // $cache->delete($cacheKey); // } $cache->set($cacheKey, $token, config('jwt.ttl') * 60); return $tokenInfo; } /** * 获取头部Token. * @return mixed */ public function getHeaderToken() { return request()->header(CommonConstant::X_TOKEN_NAME, null); } /** * 加密X-TOKEN头部信息. * @param array $info * @return false|string */ public function encodeHeaderTokenInfo(array $info) { $token = data_get($info, 'token', ''); $deviceNo = data_get($info, 'device_no', ''); $deviceType = data_get($info, 'device_type', ''); $fingerHash = data_get($info, 'finger_hash', ''); $arrData = [ 'token' => $token, 'device_no' => $deviceNo, 'device_type' => $deviceType, 'finger_hash' => $fingerHash, ]; $handshake = CommonConstant::getHandShake(); if (!empty($handshake)) { $arrMap = CommonConstant::getHandSnakeKey($handshake); $data = hand_encrypt($arrData, $arrMap['key']); } else { $data = json_encode($arrData, JSON_UNESCAPED_UNICODE); } return $data; } /** * 解密头部X-Token信息. * @param string $enStr * @return array|mixed */ public function decodeHeaderTokenInfo($enStr) { $data = []; $isValidMg = false; if (class_exists('\Modules\Manage\Services\AuthService')) { $service = make(\Modules\Manage\Services\AuthService::class); // 如果有效后台header,则直接不加密,进行明文通讯. $isValidMg = $service->checkValidMgHeaderHandShake(); } // 先拿系统里当前flag. $handshake = CommonConstant::getHandShake(); if (!$isValidMg) { if (!empty($handshake)) { $inputData = request()->all(); $inputHandShake = $inputData['handshake'] ?? $handshake; $handshake = $inputHandShake; $originData = $enStr; $arrMap = CommonConstant::getHandSnakeKey($handshake); if (!is_string($originData)) { throw new ApiException('数据格式有误3'); } try { $data = json_decode(hand_decrypt($originData, $arrMap['key'], ''), true); } catch (\Throwable $exception) { throw new ApiException('数据格式有误4'); } } else { $data = []; if (!empty($enStr) && is_string($enStr)) { $data = json_decode($enStr, true); } } } else { // TODO 为了满足android在postmain里拿到解密的数据,兼容header是加密的情况. if (!empty($enStr)) { if (substr($enStr, 0, 1) == '{') { $data = json_decode($enStr, true); } else { $arrMap = CommonConstant::getHandSnakeKey($handshake); $data = json_decode(hand_decrypt($enStr, $arrMap['key'], ''), true); } } } return $data; } /** * 获取Token中的UserId * @return string */ public function getUserId() { $user_id = ''; $enToken = $this->getHeaderToken(); $arrTokenInfo = $this->decodeHeaderTokenInfo($enToken); $token = strval(data_get($arrTokenInfo, 'token', '')); if (!empty($token)) { $jwtRepository = make(JwtRepository::class); $validateResult = $jwtRepository->validateToken($token, $this->jwtAud); if ($validateResult['is_valid']) { $user_id = $validateResult['token_obj']->claims()->get('user_id'); } } return $user_id; //是用户邀请码,非用户id(安全设计) } /** * 从Token中获取用户信息. * @return array ['user_id', 'device_no', 'device_type'] */ public function getTokenUserInfo() : array { $userId = $deviceNo = $deviceType = ''; $enToken = $this->getHeaderToken(); $arrTokenInfo = $this->decodeHeaderTokenInfo($enToken); $token = strval(data_get($arrTokenInfo, 'token', '')); if (!empty($token)) { $jwtRepository = make(JwtRepository::class); $validateResult = $jwtRepository->validateToken($token, $this->jwtAud); if ($validateResult['is_valid']) { $userId = $validateResult['token_obj']->claims()->get('user_id'); $deviceNo = $validateResult['token_obj']->claims()->get('device_no'); $deviceType = $validateResult['token_obj']->claims()->get('device_type'); } } $data = [ 'user_id' => $userId, //是用户邀请码,非用户id(安全设计) 'device_no' => $deviceNo, 'device_type' => $deviceType, ]; return $data; } }