WechatAuthenticatedService.php 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. <?php
  2. /**
  3. * @Name
  4. * @Description
  5. * @Author 刘学玺
  6. * @Date 2024/3/25 17:00
  7. */
  8. namespace App\Http\Services\Frontend\Client\Auth;
  9. use App\Exceptions\ApiException;
  10. use App\Http\Services\Frontend\Client\Common\AuthService;
  11. use App\Http\Services\Frontend\Client\Common\SmsService;
  12. use App\Http\Services\Service;
  13. use App\Models\Member\User;
  14. use App\Models\WechatUser;
  15. use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
  16. use Illuminate\Http\JsonResponse;
  17. use Illuminate\Http\Response;
  18. use Illuminate\Support\Facades\Cache;
  19. use Illuminate\Support\Facades\DB;
  20. use Illuminate\Support\Str;
  21. use Overtrue\LaravelWeChat\EasyWeChat;
  22. class WechatAuthenticatedService extends Service
  23. {
  24. /**
  25. * @throws InvalidArgumentException
  26. */
  27. public function oauth($data): array
  28. {
  29. $wechat = EasyWeChat::officialAccount();
  30. $oauth = $wechat->getOAuth();
  31. $scopes = $data['scopes'] ?: 'snsapi_base';
  32. //callback_url 是授权回调的URL
  33. //生成完整的授权URL
  34. $redirectUrl = $oauth->scopes([$scopes])->redirect($data['redirect_url']);
  35. return ['redirectUrl' => $redirectUrl];
  36. }
  37. /**
  38. * @throws InvalidArgumentException
  39. */
  40. public function callback(array $params): array
  41. {
  42. $wechat = EasyWeChat::officialAccount();
  43. $oauth = $wechat->getOAuth();
  44. // 获取 OAuth 授权用户信息
  45. $wechat_user = $oauth->userFromCode($params['code']);
  46. //$wechat_user = $user->toArray();
  47. $data = [
  48. 'openid' => $wechat_user->getId() ?? $wechat_user->getTokenResponse()['openid']
  49. ];
  50. $avatar = $wechat_user->getAvatar();
  51. $avatar && ($data['avatar'] = $avatar);
  52. $nickname = $wechat_user->getNickname();
  53. $nickname && ($data['nickname'] = $nickname);
  54. \App\Models\Wechat\User::query()->create($data);
  55. $userIsExists = User::query()->where('openid', $data['openid'])->exists();
  56. $data['bindUser'] = true;
  57. if (!$userIsExists) {
  58. // $user_id = User::query()->create($data)->id;
  59. // $user = User::query()->find($user_id);
  60. $data['bindUser'] = false;
  61. }
  62. // $isExits = $this->hasOpenID($data['openid']);
  63. // 是否已存在
  64. // !$isExits && $this->create($data);
  65. // $wechatUser = WechatUser::query()->with('user.info')->where('openid', $data['openid'])->first();
  66. // return $this->success('', ['wechatUser' => $wechatUser->toArray()]);
  67. return $data;
  68. }
  69. private function hasOpenID($openId): bool
  70. {
  71. return false;
  72. // return WechatUser::query()->where('openid', $openId)->exists();
  73. }
  74. /**
  75. * @throws ApiException
  76. */
  77. public function bind(array $params): void
  78. {
  79. $mobile = $params['mobile'];
  80. $code = $params['code'];
  81. $openid = $params['open_id'];
  82. // 验证验证码
  83. $verifyCodeResult = (new SmsService())->verifyCode($mobile, $code);
  84. !$verifyCodeResult && self::error('验证码错误!', 400);
  85. // 获取微信信息
  86. // $data = [
  87. // 'openid' => $params['openid'],
  88. // 'avatar' => $params['avatar'],
  89. // 'nickname' => $params['nickname'],
  90. // ];
  91. $register_ip = request()->getClientIp();
  92. // 获取绑定用户
  93. User::query()->updateOrCreate(['openid' => $openid], ['openid' => $openid, 'mobile' => $mobile, 'register_ip' => $register_ip]);
  94. }
  95. /**
  96. * @throws ApiException
  97. */
  98. public function store($data): array
  99. {
  100. // 公众号OpenID
  101. $openID = $data['open_id'];
  102. $autoRegister = $data['auto_register'] ?? 0;
  103. $user = User::query()->where('openid', $openID)->first();
  104. if (!$user && $autoRegister) {
  105. // 获取微信信息
  106. $wechatUser = \App\Models\Wechat\User::query()->where(['openid' => $openID])->first();
  107. // 创建用户信息
  108. $user_id = User::query()->create(['nickname' => $wechatUser['nickname'], 'avatar' => $wechatUser['avatar'], 'openid' => $openID])->id;
  109. $user = User::query()->find($user_id);
  110. }
  111. $token = (new AuthService)->store($user);
  112. return ['token' => $token];
  113. }
  114. public function create1($data): Response
  115. {
  116. // 判断验证码
  117. (new SmsService())->verify($data['mobile'], $data['code']);
  118. $where = ['mobile' => $data['mobile'], 'type' => 0];
  119. $exists = User::query()->where($where)->exists();
  120. if (!$exists) User::query()->create($where);
  121. // 绑定公众号
  122. $user = User::query()->where($where)->first();
  123. $user->open_id = $data['openid'];
  124. $user->save();
  125. return (new AuthService)->store($user);
  126. }
  127. // 发送短信
  128. public function send($data): Response
  129. {
  130. $mobile = $data['mobile'];
  131. $sms = new SmsService();
  132. return $sms->send($mobile, 0, 2);
  133. }
  134. /**
  135. * 公众号签名
  136. * @throws ApiException
  137. */
  138. public function getSignature(array $data): array
  139. {
  140. $wechat = EasyWeChat::officialAccount();
  141. $ticket = $wechat->getTicket();
  142. $jsapi_ticket = $ticket->getTicket();
  143. // 当前URL
  144. $url = request('url', request()->header('referer'));
  145. // 生成签名
  146. $nonceStr = 'xiaoding' . Str::random(20); // 请用随机算法生成
  147. $timestamp = time(); // 当前时间戳
  148. $signatureStr = "jsapi_ticket={$jsapi_ticket}&noncestr={$nonceStr}&timestamp={$timestamp}&url={$url}";
  149. $signature = sha1($signatureStr);
  150. $wechatConfig = $wechat->getConfig();
  151. // 数据用于前端显示
  152. $signPackage = [
  153. "appId" => $wechatConfig['app_id'],
  154. "nonceStr" => $nonceStr,
  155. "timestamp" => $timestamp,
  156. "url" => $url,
  157. "signature" => $signature,
  158. "rawString" => $signatureStr
  159. ];
  160. // $sign = $this->makeSha1Sign($signData); // 生成微信签名
  161. //
  162. // $signData['signature'] = $sign;
  163. return $signPackage;
  164. //
  165. //
  166. // $access_token = $this->getAccessToken();
  167. //
  168. // // 这里的$token就是你在微信公众平台设置的Token
  169. // // 这里的$timestamp就是时间戳
  170. // // 这里的$nonce就是随机数
  171. // // 这里的$msg就是发送给微信服务器的数据
  172. //
  173. // // 将token、timestamp、nonce三个参数按字典序排序
  174. // $array = array($token, $timestamp, $nonce, $msg);
  175. // sort($array, SORT_STRING);
  176. //
  177. // // 将排序后的三个参数拼接成一个字符串
  178. // $str = implode($array);
  179. //
  180. // // 使用sha1算法计算出摘要
  181. // $signature = sha1($str);
  182. //
  183. // // 转换成小写
  184. // $signature = strtolower($signature);
  185. //
  186. // return $signature;
  187. }
  188. //生成 sha1 签名
  189. private function makeSha1Sign($array): string
  190. {
  191. //升序数组的键
  192. ksort($array);
  193. $params = urldecode(http_build_query($array));
  194. //字符串SHA1
  195. return sha1($params);
  196. }
  197. //获取微信access_token
  198. /**
  199. * @throws ApiException
  200. */
  201. private function getAccessToken()
  202. {
  203. $tokeUrl = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" . config('easywechat.official_account.default.app_id') . "&secret=" . config('easywechat.official_account.default.secret');
  204. $tokenResp = file_get_contents($tokeUrl);
  205. !$tokenResp && self::error('token 服务器返回失败');
  206. $tokenData = json_decode($tokenResp, true);
  207. if (!isset($tokenData['access_token'])) self::error($tokenData['errmsg']);
  208. return $tokenData['access_token'];
  209. }
  210. //获取微信ticket
  211. /**
  212. * @throws ApiException
  213. */
  214. private function getTicket($access_token)
  215. {
  216. $ticketUrl = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=' . $access_token . '&type=jsapi';
  217. $ticketResp = file_get_contents($ticketUrl);
  218. if (!$ticketResp) return self::error('ticket 获取失败');
  219. $ticketData = json_decode($ticketResp, true);
  220. if (!isset($ticketData['ticket'])) return self::error('ticket 解析错误');
  221. $ticket = $ticketData['ticket'];
  222. cache::set('wechart_share_ticket', $ticket, 7200);
  223. return $ticket;
  224. }
  225. }