Token.php 8.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. <?php
  2. /**
  3. * lemocms
  4. * ============================================================================
  5. * 版权所有 2018-2027 lemocms,并保留所有权利。
  6. * 网站地址: https://www.lemocms.com
  7. * ----------------------------------------------------------------------------
  8. * 采用最新Thinkphp6实现
  9. * ============================================================================
  10. * Author: yuege
  11. * Date: 2019/10/3
  12. */
  13. namespace lemo\api;
  14. use think\facade\Request;
  15. use lemo\api\Send;
  16. use lemo\api\Oauth;
  17. use think\facade\Cache;
  18. use app\api\util\wxBizDataCrypt;
  19. use app\common\model\WxFans;
  20. use think\facade\Db;
  21. /**
  22. * 生成token
  23. */
  24. class Token
  25. {
  26. use Send;
  27. /**
  28. * 请求时间差
  29. */
  30. public static $timeDif = 10000;
  31. public static $accessTokenPrefix = 'accessToken_';
  32. public static $refreshAccessTokenPrefix = 'refreshAccessToken_';
  33. public static $expires = 7200;
  34. public static $refreshExpires = 3600*24*30; //刷新token过期时间
  35. /**
  36. * 测试appid,正式请数据库进行相关验证
  37. */
  38. public static $appid = '';
  39. /**
  40. * appsecret
  41. */
  42. public static $appsecret = '';
  43. /**
  44. * 构造方法
  45. * @param Request $request Request对象
  46. */
  47. public function __construct(Request $request)
  48. {
  49. $this->request = Request::instance();
  50. $appid = Request::post('appid');
  51. $oauth2_client = Db::name('oauth2_client')->where('appid', $appid)->find();
  52. if (!$oauth2_client) {
  53. return self::returnMsg(401, 'Invalid authorization credentials');
  54. }
  55. self::$appid = $oauth2_client['appid'];
  56. self::$appsecret = $oauth2_client['appsecret'];
  57. }
  58. /**
  59. * 生成token $accessToken
  60. */
  61. public function accessToken(Request $request)
  62. {
  63. //参数验证
  64. $validate = new \lemo\api\validate\Token;
  65. if (!$validate->check(Request::post())) {
  66. return self::returnMsg(401, $validate->getError());
  67. }
  68. self::checkParams(Request::post()); //参数校验
  69. //数据库已经有一个用户,这里需要根据input('mobile')去数据库查找有没有这个用户
  70. $userInfo = self::getUser(Request::post('mobile'));
  71. //虚拟一个uid返回给调用方
  72. try {
  73. $accessToken = self::setAccessToken(array_merge($userInfo, Request::post())); //传入参数应该是根据手机号查询改用户的数据
  74. return self::returnMsg(200, 'success', $accessToken);
  75. } catch (\Exception $e) {
  76. return self::returnMsg(500, 'fail', $e);
  77. }
  78. }
  79. /** 小程序
  80. * @param string $code
  81. * @param string $encryptedData
  82. * @param string $iv
  83. * @param array $appInfo
  84. */
  85. public function getOpenId($code = '',$encryptedData = '',$iv = '',$appInfo = [])
  86. {
  87. $result = json_decode(file_get_contents("https://api.weixin.qq.com/sns/jscode2session?appid=" . $appInfo['wx_appid'] . "&secret=" . $appInfo['wx_appsecret'] . "&js_code=" . $code . "&grant_type=authorization_code"), true);
  88. if(empty($result['session_key'])){
  89. return $this->returnmsg(401,'获取token失败!'.$result['errmsg']);
  90. }else{
  91. $pc = new wxBizDataCrypt($appInfo['wx_appid'], $result['session_key']);
  92. $data = $pc->decryptData($encryptedData, $iv); //解密用户基础信息
  93. $data = json_decode($data, true);
  94. if (!empty($data['openId'])) {
  95. if (isset($data['unionId'])) { //含有unionid
  96. $is_unionid['is_unionid'] = true;
  97. $userInfo = WxFans::get(['unionid' => $data['unionId']]); //按照unionid查找
  98. if(empty($userInfo)){
  99. $userInfo = WxFans::get(['openid' => $data['openId']]); //按照openid查找
  100. }
  101. } else {
  102. $is_unionid['is_unionid'] = false;
  103. $userInfo = WxFans::get(['openid' => $data['openId']]); //按照openid查找
  104. }
  105. $userAdd['openid'] = $data['openId'];
  106. $userAdd['unionid'] = isset($data['unionId']) ? $data['unionId'] : '';
  107. $userAdd['nickname'] = $data['nickName'];
  108. $userAdd['headimgurl'] = $data['avatarUrl'];
  109. $userAdd['sex'] = $data['gender'];
  110. $userAdd['province'] = $data['province'];
  111. $userAdd['country'] = $data['country'];
  112. if(empty($userInfo)){ //用户没有在fans表里面
  113. $userAdd['subscribe_scene'] = 'WEIXIN';
  114. $userAdd['source'] = 2;
  115. WxFans::create($userAdd); //插入到粉丝表
  116. }else{
  117. $userAdd['update_time'] = time();
  118. WxFans::where('fans_id',$userInfo['fans_id'])->update($userAdd);
  119. $userAdd['uid'] = $userInfo['id'];
  120. }
  121. return $userAdd;
  122. }else{
  123. return $this->returnmsg(401,'获取token失败!解析数据失败');
  124. }
  125. }
  126. }
  127. /**
  128. * token 过期 刷新token
  129. */
  130. public function refresh($refresh_token = '', $appid = '')
  131. {
  132. $cache_refresh_token = Cache::get(self::$refreshAccessTokenPrefix . $appid); //查看刷新token是否存在
  133. if (!$cache_refresh_token) {
  134. return self::returnMsg(401, 'fail', 'refresh_token is null');
  135. } else {
  136. if ($cache_refresh_token !== $refresh_token) {
  137. return self::returnMsg(401, 'fail', 'refresh_token is error');
  138. } else { //重新给用户生成调用token
  139. $data['appid'] = $appid;
  140. $accessToken = self::setAccessToken($data);
  141. return self::returnMsg(200, 'success', $accessToken);
  142. }
  143. }
  144. }
  145. /**
  146. * 参数检测和验证签名
  147. */
  148. public static function checkParams($params = [])
  149. {
  150. //时间戳校验
  151. if (abs($params['timestamp'] - time()) > self::$timeDif) {
  152. return self::returnMsg(401, '请求时间戳与服务器时间戳异常', 'timestamp:' . time());
  153. }
  154. //appid检测,这里是在本地进行测试,正式的应该是查找数据库或者redis进行验证
  155. if ($params['appid'] !== self::$appid) {
  156. return self::returnMsg(401, 'appid 错误');
  157. }
  158. //签名检测
  159. $sign = Oauth::makeSign($params, self::$appsecret);
  160. if ($sign !== $params['sign']) {
  161. return self::returnMsg(401, 'sign错误', 'sign:' . $sign);
  162. }
  163. }
  164. /**
  165. * 设置AccessToken
  166. * @param $clientInfo
  167. * @return int
  168. */
  169. protected function setAccessToken($clientInfo)
  170. {
  171. //生成令牌
  172. $accessToken = self::buildAccessToken();
  173. $refresh_token = self::getRefreshToken($clientInfo['appid']);
  174. $accessTokenInfo = [
  175. 'access_token' => $accessToken,//访问令牌
  176. 'expires_time' => time() + self::$expires, //过期时间时间戳
  177. 'refresh_token' => $refresh_token,//刷新的token
  178. 'refresh_expires_time' => time() + self::$refreshExpires, //过期时间时间戳
  179. 'client' => $clientInfo,//用户信息
  180. ];
  181. self::saveAccessToken($accessToken, $accessTokenInfo); //保存本次token
  182. self::saveRefreshToken($refresh_token, $clientInfo['appid']);
  183. return $accessTokenInfo;
  184. }
  185. /**
  186. * 刷新用的token检测是否还有效
  187. */
  188. public static function getRefreshToken($appid = '')
  189. {
  190. return Cache::get(self::$refreshAccessTokenPrefix . $appid) ? Cache::get(self::$refreshAccessTokenPrefix . $appid) : self::buildAccessToken();
  191. }
  192. /**
  193. * 生成AccessToken
  194. * @return string
  195. */
  196. protected static function buildAccessToken($lenght = 32)
  197. {
  198. //生成AccessToken
  199. $str_pol = "1234567890ABCDEFGHIJKLMNOPQRSTUVWXYZ123456789abcdefghijklmnopqrstuvwxyz";
  200. return substr(str_shuffle($str_pol), 0, $lenght);
  201. }
  202. /**
  203. * 存储token
  204. * @param $accessToken
  205. * @param $accessTokenInfo
  206. */
  207. protected static function saveAccessToken($accessToken, $accessTokenInfo)
  208. {
  209. //存储accessToken
  210. cache(self::$accessTokenPrefix . $accessToken, $accessTokenInfo, self::$expires);
  211. }
  212. /**
  213. * 刷新token存储
  214. * @param $accessToken
  215. * @param $accessTokenInfo
  216. */
  217. protected static function saveRefreshToken($refresh_token, $appid)
  218. {
  219. //存储RefreshToken
  220. cache(self::$refreshAccessTokenPrefix . $appid, $refresh_token, self::$refreshExpires);
  221. }
  222. protected static function getUser($mobile)
  223. {
  224. $user = Db::name('user')->where('mobile', $mobile)->find();
  225. if ($user) {
  226. $user['uid'] = $user['id'];
  227. return $user;
  228. } else {
  229. return self::returnMsg(401, '用户不存在');
  230. }
  231. }
  232. }