TokenService.php 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237
  1. <?php
  2. namespace app\core\util;
  3. use app\core\model\routine\Token;
  4. use service\CacheService;
  5. class TokenService
  6. {
  7. //加密分割key
  8. private static $KEY='fb';
  9. //10位加密key
  10. private static $sKey='crmeb12345';
  11. //相隔付
  12. private static $seperater = "{&&}";
  13. //是否开启辅助验证
  14. private static $isAuxiliary=false;
  15. //加密方式 为空为普通加密
  16. private static $encryptType='DES';
  17. //实例化类
  18. private static $instance=null;
  19. //构造单例模式
  20. private function __construct()
  21. {
  22. }
  23. /*
  24. * 初始化类
  25. * @return object
  26. * */
  27. public static function instance()
  28. {
  29. if(is_null(self::$instance)) self::$instance=new self();
  30. return self::$instance;
  31. }
  32. /*
  33. * 设置加密方式
  34. * @param $encryptType 加密类型
  35. * */
  36. public function setEncryptType($encryptType='DES')
  37. {
  38. self::$encryptType=$encryptType;
  39. }
  40. /*
  41. * 验证token
  42. * @param string $token token
  43. * @param boolean $isSkip 是否跳过验证
  44. * @return Boolean | array
  45. * */
  46. public static function checkToken($token,$isSkip=false)
  47. {
  48. self::InitSkey();
  49. //跳过验证
  50. if($isSkip && !$token) return true;
  51. //解密token
  52. if(strtolower(self::$encryptType)==='des'){
  53. $data=explode(self::$seperater,self::DesDecrypt($token));
  54. }else{
  55. $data=explode(self::$seperater,self::deCode($token));
  56. }
  57. //验证是否为数组 数组length为6
  58. if(is_array($data) && count($data) == 7){
  59. //第一位不能为空
  60. if(empty($data[0])) return false;
  61. //验证公钥是否被篡改
  62. if($data[3]!=self::$sKey) return false;
  63. //验证token是否过期
  64. if((int)$data[5]<time()) return false;
  65. //验证当前用户加密的随机字符串
  66. if(self::$isAuxiliary===true) if(!Token::checkRandString($data[0],$data[2])) return false;
  67. //返回第一位和二位数据
  68. return [$data[0],$data[1]];
  69. }
  70. return false;
  71. }
  72. /*
  73. * 获取token
  74. * @param string $string 加密字符串
  75. * @param string $openid 加密openid
  76. * @param int $valid_peroid token过期时间默认5天 259200
  77. * @param string $randstring 随机字符串提供辅助验证token
  78. * @return token
  79. * */
  80. public static function getToken($string=1,$openid='0',$randstring='0',$valid_peroid=259200)
  81. {
  82. self::InitSkey();
  83. if(self::$isAuxiliary===true) {
  84. $randstring = self::createNonceStr();
  85. $res = Token::SetRandString($string, $randstring);
  86. if (!$res) return false;
  87. }
  88. return self::enToken($string,$openid,$randstring,$valid_peroid);
  89. }
  90. /*
  91. * 获取token公钥并缓存
  92. * @param boolean $debuy 是否为调试模式
  93. * @param int $default 默认缓存时效
  94. * */
  95. private static function InitSkey($debuy=true,$default=3600)
  96. {
  97. if($token_skey=CacheService::get('token_skey'))
  98. self::$sKey=$token_skey;
  99. else{
  100. $token_skey=SystemConfigService::get('token_skey');
  101. if(!$token_skey && $debuy===false) exception('请先配置小程序访问TO_kEN [token_skey] 公钥');
  102. if($token_skey){
  103. CacheService::set('token_skey',$token_skey,$default);
  104. self::$sKey=$token_skey;
  105. }
  106. }
  107. }
  108. /*
  109. * 加密token字符串
  110. * @param string $string 加密字符串
  111. * @param string $openid 加密openid
  112. * @param int $valid_peroid token过期时间默认5天
  113. * @return token
  114. * */
  115. private static function enToken($string,$openid='0',$randString='',$valid_peroid=259200)
  116. {
  117. //加密字符串 + 相隔付 + openid + 相隔付 + 随机字符串 + 相隔付 + 加密字符串 + 相隔付 + 当前时间 + 相隔付 + token过期时间 + 相隔付
  118. $to_ken=$string.self::$seperater.
  119. $openid.self::$seperater.
  120. $randString.self::$seperater.
  121. self::$sKey.self::$seperater.
  122. time().self::$seperater.
  123. (time()+$valid_peroid).self::$seperater;
  124. if(strtolower(self::$encryptType)==='des'){
  125. $token=self::DesNncrypt($to_ken);
  126. }else {
  127. $token = self::enCode($to_ken);
  128. }
  129. return $token;
  130. }
  131. /**
  132. * 通用加密
  133. * @param String $string 需要加密的字串
  134. * @return String
  135. */
  136. private static function enCode($string) {
  137. $skey = array_reverse(str_split(self::$KEY));
  138. $strArr = str_split(base64_encode($string));
  139. $strCount = count($strArr);
  140. foreach ($skey as $key => $value) {
  141. $key < $strCount && $strArr[$key].=$value;
  142. }
  143. return str_replace('=', 'O0O0O', join('', $strArr));
  144. }
  145. /**
  146. * 通用解密
  147. * @param String $string 需要解密的字串
  148. * @param String $skey 解密KEY
  149. * @return String
  150. */
  151. private static function deCode($string) {
  152. $skey = array_reverse(str_split(self::$KEY));
  153. $strArr = str_split(str_replace('O0O0O', '=', $string), 2);
  154. $strCount = count($strArr);
  155. foreach ($skey as $key => $value) {
  156. $key < $strCount && $strArr[$key] = rtrim($strArr[$key], $value);
  157. }
  158. return base64_decode(join('', $strArr));
  159. }
  160. /*
  161. * DES 加密
  162. * @param string $data 待加密明文
  163. * @param string $deskey 加密秘钥
  164. * @return string
  165. **/
  166. private static function DesNncrypt($data, $key='')
  167. {
  168. $deskey=$key=='' ? self::$sKey : $key;
  169. if(strlen($deskey) > 8) $deskey=substr($deskey,0,8);//php加密秘钥只能为8位
  170. if(function_exists('openssl_encrypt')){
  171. $data = openssl_encrypt($data, 'AES-128-ECB', $deskey, OPENSSL_RAW_DATA);
  172. $data = strtolower(bin2hex($data));
  173. return $data;
  174. }else{
  175. $blocksize = mcrypt_get_block_size(MCRYPT_DES,MCRYPT_MODE_ECB);
  176. $pad = $blocksize - (strlen($data) % $blocksize);
  177. $data1 = $data. str_repeat(chr($pad),$pad);
  178. $iv = mcrypt_create_iv(mcrypt_get_iv_size(MCRYPT_DES,MCRYPT_MODE_ECB),MCRYPT_RAND); //初始化向量
  179. $data_encrypt = mcrypt_encrypt(MCRYPT_DES,$deskey,$data1,MCRYPT_MODE_ECB);//加密函数
  180. $datastr = bin2hex($data_encrypt);
  181. return $datastr;
  182. }
  183. }
  184. /*
  185. * DES 解密
  186. * @param string $data 待解密密文
  187. * @param string $deskey 加密秘钥
  188. * @return string
  189. */
  190. private static function DesDecrypt($endata,$deskey=''){
  191. $deskey=$deskey=='' ? self::$sKey : $deskey;
  192. if(strlen($deskey) > 8) $deskey=substr($deskey,0,8);//php加密秘钥只能为8位
  193. if(function_exists('openssl_encrypt')){
  194. $decrypted = openssl_decrypt(hex2bin($endata), 'AES-128-ECB', $deskey, OPENSSL_RAW_DATA);
  195. return $decrypted;
  196. }else{
  197. $de_datastr = $endata !== false && preg_match('/^[0-9a-fA-F]+$/i',$endata) ? pack('H*',$endata):false;
  198. $data_decrypt = mcrypt_decrypt(MCRYPT_DES,$deskey,$de_datastr,MCRYPT_MODE_ECB,null);//解密函数
  199. $ret = self::_pkcs5Unpad($data_decrypt);
  200. $de_data = trim($ret);
  201. return $de_data;
  202. }
  203. }
  204. private static function _pkcs5Unpad($text){
  205. $pad = ord($text{strlen($text)-1});
  206. if($pad > strlen($text)) return false;
  207. if(strspn($text,chr($pad),strlen($text)-$pad) != $pad) return false;
  208. $ret = substr($text,0,-1*$pad);
  209. return trim($ret);
  210. }
  211. /**
  212. * 生成随机填充码
  213. * @return string 10位
  214. * @return string
  215. */
  216. private static function createNonceStr($length = 5)
  217. {
  218. $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
  219. $str = "";
  220. for ($i = 0; $i < $length; $i++) {
  221. $str .= substr($chars, mt_rand(0, strlen($chars) - 1), 1);
  222. }
  223. return "crmeb".$str;
  224. }
  225. }