WechatAuthService.php 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. <?php
  2. // +----------------------------------------------------------------------
  3. // | Niucloud-admin 企业快速开发的saas管理平台
  4. // +----------------------------------------------------------------------
  5. // | 官方网址:https://www.niucloud.com
  6. // +----------------------------------------------------------------------
  7. // | niucloud团队 版权所有 开源版本可自由商用
  8. // +----------------------------------------------------------------------
  9. // | Author: Niucloud Team
  10. // +----------------------------------------------------------------------
  11. namespace app\service\api\wechat;
  12. use app\dict\member\MemberLoginTypeDict;
  13. use app\dict\member\MemberRegisterTypeDict;
  14. use app\dict\scan\ScanDict;
  15. use app\service\api\login\LoginService;
  16. use app\service\api\login\RegisterService;
  17. use app\service\api\member\MemberConfigService;
  18. use app\service\api\member\MemberService;
  19. use app\service\core\scan\CoreScanService;
  20. use app\service\core\wechat\CoreWechatFansService;
  21. use app\service\core\wechat\CoreWechatServeService;
  22. use core\base\BaseApiService;
  23. use core\exception\ApiException;
  24. use core\exception\AuthException;
  25. use think\db\exception\DataNotFoundException;
  26. use think\db\exception\DbException;
  27. use think\db\exception\ModelNotFoundException;
  28. /**
  29. * 微信配置模型
  30. * Class WechatConfigService
  31. * @package app\service\core\wechat
  32. */
  33. class WechatAuthService extends BaseApiService
  34. {
  35. public $core_wechat_serve_service;
  36. public function __construct()
  37. {
  38. parent::__construct();
  39. $this->core_wechat_serve_service = new CoreWechatServeService();
  40. }
  41. /**
  42. * 网页授权
  43. * @param string $url
  44. * @param string $scopes
  45. * @return array
  46. */
  47. public function authorization(string $url = '', string $scopes = 'snsapi_base')
  48. {
  49. //todo 业务落地
  50. return ['url' => $this->core_wechat_serve_service->authorization(0, $url, $scopes)];
  51. }
  52. /**
  53. * 处理授权回调
  54. * @param string $code
  55. * @return array
  56. */
  57. public function userFromCode(string $code)
  58. {
  59. $userinfo = $this->core_wechat_serve_service->userFromCode(0, $code);
  60. if (empty($userinfo)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
  61. $token_response = $userinfo->getTokenResponse();
  62. if (empty($token_response)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
  63. $scope = $token_response['scope'];
  64. if ($scope == 'snsapi_base') {//静默授权
  65. $openid = $token_response['openid'] ?? '';
  66. } else {
  67. $openid = $userinfo->getId();//对应微信的 openid
  68. $nickname = $userinfo->getNickname();//对应微信的 nickname
  69. $avatar = $userinfo->getAvatar();//对应微信的 头像地址
  70. }
  71. $unionid = $userinfo->getRaw()[ 'unionid' ] ?? '';
  72. if (empty($openid)) throw new ApiException('WECHAT_EMPOWER_NOT_EXIST');
  73. //todo 这儿还可能会获取用户昵称 头像 性别 ....用以更新会员信息
  74. return [$avatar ?? '', $nickname ?? '', $openid, $unionid];
  75. //todo 业务落地
  76. }
  77. /**
  78. * 登录通过code
  79. * @param string $code
  80. * @return array|string[]|null
  81. * @throws DataNotFoundException
  82. * @throws DbException
  83. * @throws ModelNotFoundException
  84. */
  85. public function loginByCode(string $code)
  86. {
  87. [ $avatar, $nickname, $openid, $unionid ] = $this->userFromCode($code);
  88. return $this->login($openid, $nickname, $avatar, $unionid);
  89. }
  90. /**
  91. * 公众号登录
  92. * @param string $openid
  93. * @param string $nickname
  94. * @param string $avatar
  95. * @return array|null
  96. * @throws DataNotFoundException
  97. * @throws DbException
  98. * @throws ModelNotFoundException
  99. */
  100. public function login(string $openid, string $nickname = '', string $avatar = '', string $unionid = '')
  101. {
  102. $member_service = new MemberService();
  103. $member_info = $member_service->findMemberInfo(['wx_openid' => $openid]);
  104. if ($member_info->isEmpty() && !empty($unionid)) {
  105. $member_info = $member_service->findMemberInfo([ 'wx_unionid' => $unionid ]);
  106. if (!$member_info->isEmpty()) {
  107. $member_info->wx_openid = $openid;
  108. }
  109. }
  110. if ($member_info->isEmpty()) {
  111. $config = (new MemberConfigService())->getLoginConfig();
  112. $is_auth_register = $config['is_auth_register'];
  113. // 去掉强制绑定手机号判断,否则开启强制绑定的情况下公众号第三方注册无法注册
  114. if ($is_auth_register == 1) {
  115. return $this->register($openid, '', $nickname, $avatar, $unionid);
  116. } else {
  117. return ['avatar' => $avatar, 'nickname' => $nickname, 'openid' => $openid, 'unionid' => $unionid];
  118. }
  119. } else {
  120. //可能会更新用户和粉丝表
  121. $login_service = new LoginService();
  122. return $login_service->login($member_info, MemberLoginTypeDict::WECHAT);
  123. }
  124. }
  125. /**
  126. * 同步数据
  127. * @param string $code
  128. * @return true
  129. */
  130. public function sync(string $code)
  131. {
  132. [$avatar, $nickname, $openid] = $this->userFromCode($code);
  133. //更新粉丝
  134. $core_wechat_fans_service = new CoreWechatFansService();
  135. //这儿或许可以异步
  136. $core_wechat_fans_service->edit(0, $openid, ['avatar' => $avatar, 'nickname' => $nickname]);
  137. $member_service = new MemberService();
  138. $member_info = $member_service->findMemberInfo(['wx_openid' => $openid]);
  139. if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在
  140. $member_service->editByFind($member_info, ['headimg' => $avatar, 'nickname' => $nickname]);
  141. return true;
  142. }
  143. /**
  144. * 注册
  145. * @param string $openid
  146. * @param string $mobile
  147. * @param string $nickname
  148. * @param string $avatar
  149. * @param string $wx_unionid
  150. * @return array
  151. * @throws DataNotFoundException
  152. * @throws DbException
  153. * @throws ModelNotFoundException
  154. */
  155. public function register(string $openid, string $mobile = '', string $nickname = '', string $avatar = '', string $wx_unionid = '')
  156. {
  157. $member_service = new MemberService();
  158. $member_info = $member_service->findMemberInfo(['wx_openid' => $openid]);
  159. if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册
  160. if (!empty($wx_unionid)) {
  161. $member_info = $member_service->findMemberInfo([ 'wx_unionid' => $wx_unionid ]);
  162. if (!$member_info->isEmpty()) throw new AuthException('MEMBER_IS_EXIST');//账号已存在, 不能在注册
  163. }
  164. $register_service = new RegisterService();
  165. return $register_service->register($mobile,
  166. [
  167. 'wx_openid' => $openid,
  168. 'nickname' => $nickname,
  169. 'headimg' => $avatar,
  170. 'wx_unionid' => $wx_unionid
  171. ],
  172. MemberRegisterTypeDict::WECHAT
  173. );
  174. }
  175. /**
  176. * 获取jssdkconfig
  177. * @param string $url
  178. * @return array|string
  179. */
  180. public function jssdkConfig(string $url = '')
  181. {
  182. return $this->core_wechat_serve_service->jssdkConfig(0, $url);
  183. }
  184. /**
  185. * 扫码登录
  186. * @return array
  187. */
  188. public function scanLogin()
  189. {
  190. $data = [
  191. 'channel' => $this->channel,
  192. ];
  193. $key = (new CoreScanService())->scan(0, ScanDict::WECHAT_LOGIN, $data, 300);
  194. $url = $this->core_wechat_serve_service->scan(0, $key, 300)['url'] ?? '';
  195. return [
  196. 'url' => $url,
  197. 'key' => $key
  198. ];
  199. }
  200. /**
  201. * 更新openid(用于账号密码或手机号注册时未正常获取到openid时再次获取)
  202. * @param string $code
  203. * @return true
  204. */
  205. public function updateOpenid(string $code)
  206. {
  207. [ $avatar, $nickname, $openid, $unionid ] = $this->userFromCode($code);
  208. $member_service = new MemberService();
  209. $member = $member_service->findMemberInfo([ 'wx_openid' => $openid ]);
  210. if (!$member->isEmpty()) throw new AuthException('MEMBER_OPENID_EXIST');//openid已存在
  211. $member_info = $member_service->findMemberInfo([ 'member_id' => $this->member_id ]);
  212. if ($member_info->isEmpty()) throw new AuthException('MEMBER_NOT_EXIST');//账号不存在
  213. $member_service->editByFind($member_info, [ 'wx_openid' => $openid ]);
  214. return true;
  215. }
  216. }