Api.php 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256
  1. <?php
  2. /**
  3. * @copyright Copyright (c) 2018 https://www.sapixx.com All rights reserved.
  4. * @license Licensed (http://www.apache.org/licenses/LICENSE-2.0).
  5. * @author pillar<ltmn@qq.com>
  6. * API默认继承类
  7. */
  8. namespace app\common\controller;
  9. use app\common\model\SystemUser;
  10. use app\common\model\SystemMemberMiniapp;
  11. use app\common\model\SystemMemberWechatTpl;
  12. use app\common\facade\WechatProgram;
  13. use app\common\event\User;
  14. use think\facade\Request;
  15. use filter\Filter;
  16. use sign\Sign;
  17. class Api extends Base {
  18. protected $miniapp; //应用信息
  19. protected $miniapp_id; //应用信息ID
  20. protected $member_miniapp; //应用信息(兼容处理)
  21. protected $member_miniapp_id; //应用信息ID(兼容处理)
  22. protected $token; //验证用户
  23. protected $user; //登录后用户
  24. /**
  25. * 初始化类
  26. */
  27. protected function initialize(){
  28. parent::initialize();
  29. if(!Request::param('sapixx/d',0)){
  30. exit(json_encode(['code'=>403,'msg'=>'禁止非法访问']));
  31. }
  32. $this->miniapp = $this->apiAccess();
  33. if(!$this->miniapp){
  34. exit(json_encode(['code'=>403,'msg'=>'应用停止服务']));
  35. }
  36. $this->member_miniapp = $this->miniapp; //兼容处理
  37. $this->member_miniapp_id = $this->miniapp->id; //兼容处理
  38. $this->miniapp_id = $this->miniapp->id;
  39. $this->user = self::getUser();
  40. $this->isAppTyes($this->miniapp->miniapp->types); //判断应用类型
  41. }
  42. /**
  43. * 方法不存在
  44. */
  45. public function _empty(){
  46. return enjson(403,'未找到API地址');
  47. }
  48. /**
  49. * 读取小程序配置
  50. * @return void
  51. */
  52. public function config(){
  53. $wxconfig = [
  54. 'app_name' => $this->miniapp->appname,
  55. 'app_id' => $this->miniapp->id,
  56. 'sdk_app_id' => $this->miniapp->sdk_app_id,
  57. 'sdk_url' => $this->miniapp->sdk_url,
  58. 'navbar_color' => $this->miniapp->navbar_color ?: '#ffffff',
  59. 'navbar_style' => $this->miniapp->navbar_style ?: '#000000',
  60. ];
  61. $tpl = SystemMemberWechatTpl::getConfig($this->miniapp_id);
  62. if($tpl){
  63. $wxconfig['tplmsg'][] = $tpl->tplmsg_common_app;
  64. }
  65. return enjson(200,$wxconfig);
  66. }
  67. /**
  68. * 获取用户数据
  69. * @return void
  70. */
  71. public function getUserInfo(){
  72. $userinfo = self::getUser();
  73. if(!$userinfo){
  74. return json(['code'=>401,'msg'=>'用户认证失败']);
  75. }
  76. $data['invite_code'] = $this->user->invite_code;
  77. $data['phone_uid'] = empty($this->user->phone_uid) ? '' : en_phone($this->user->phone_uid);
  78. $data['telphone'] = $this->user->phone_uid;
  79. $data['invite_code'] = $this->user->invite_code;
  80. $data['face'] = $this->user->face;
  81. $data['nickname'] = $this->user->nickname;
  82. $data['login_time'] = date('Y-m-d',$this->user->login_time);
  83. return enjson(200,$data);
  84. }
  85. /**
  86. * 微信小程序统一登录接口
  87. */
  88. public function miniappLogin($type = 'json'){
  89. if(request()->isPost()){
  90. $data = [
  91. 'code' => Request::param('code/s'),
  92. 'user_info' => Request::param('user_info/s'),
  93. 'encrypted_data' => Request::param('encrypted_data/s'),
  94. 'iv' => Request::param('iv/s'),
  95. 'signature' => Request::param('signature/s'),
  96. 'official_uid' => Request::param('official_uid/s',''),
  97. 'invite_code' => Request::param('invite_code/s',''),
  98. ];
  99. $validate = $this->validate($data,'Miniapp.login');
  100. if(true !== $validate){
  101. return enjson(403,$validate,[],$type);
  102. }
  103. $userInfo = json_decode(htmlspecialchars_decode($data['user_info']),true);
  104. if(empty($userInfo)){
  105. return enjson(403,'用户登录失败',[],$type);
  106. }
  107. //判断是否开放平台应用(0是开发平台 1是独立应用)
  108. $rel = WechatProgram::isTypes($this->miniapp_id);
  109. if(!$rel){
  110. return enjson(403,'管理员未授权应用接入',[],$type);
  111. }
  112. $miniapp = $rel->auth->session($data['code']);
  113. if(!empty($miniapp['errcode'])){
  114. return enjson(403,'Token无效,请联系管理员',[],$type);
  115. }
  116. $nickName = Filter::filter_Emoji($userInfo['nickName']);
  117. //获取(注册/登录)数据
  118. $regdata['miniapp_uid'] = $miniapp['openid'];
  119. $regdata['session_key'] = $miniapp['session_key'];
  120. $regdata['official_uid'] = $data['official_uid']; //绑定公众号的OPENID时候用的
  121. $regdata['wechat_uid'] = empty($miniapp['unionid']) ? '' : $miniapp['unionid'];
  122. $regdata['nickname'] = $nickName ?? '微信-'.time();
  123. $regdata['avatar'] = $userInfo['avatarUrl'];
  124. $regdata['miniapp_id'] = $this->miniapp_id;
  125. $regdata['invite_code'] = $data['invite_code']; //邀请码
  126. //判断是登录还是注册
  127. $uid = SystemUser::wechatReg($regdata);
  128. if(!$uid){
  129. return enjson(403,'用户认证失败',[],$type);
  130. }
  131. //保持注册记录
  132. User::setLogin(['id'=> $uid,'nickname' => $nickName]);
  133. //返回信息
  134. $return_data['token'] = WechatProgram::createToken(['miniapp_id' => $this->miniapp_id,'uid' => $uid,'miniapp_uid' => $miniapp['openid'],'service_id' => $this->miniapp->service_id]);
  135. $return_data['uid'] = $uid;
  136. $return_data['ucode'] = create_code($uid);
  137. $return_data['session_id'] = session_id();
  138. return enjson(200,'登录成功',$return_data,$type);
  139. }else{
  140. return $this->error("404 NOT FOUND");
  141. }
  142. }
  143. /**
  144. * 生成小程序码
  145. * @param [array] $scene 格式的参数
  146. * @param [string] $page 小程序路径
  147. * @return void
  148. */
  149. public function MiniProgramCode(array $scene, $page, $name){
  150. if(request()->isPost()){
  151. $filepath = PATH_RES.'qrcode/';
  152. $response = WechatProgram::isTypes($this->miniapp_id)->app_code->getUnlimit(http_build_query($scene),['page' => Filter::filter_escape($page)]);
  153. if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
  154. $filename = $response->saveAs($filepath,md5($name));
  155. $path = '/' . str_replace('\\', '/', substr($filepath.$filename,strlen(PATH_PUBLIC)));
  156. return json(['code' => 200, 'msg' => '成功', 'data' => Request::root(true).$path]);
  157. }
  158. return enjson(404,'您的应用未上线');
  159. }
  160. }
  161. /**
  162. * 生成小程序码二维码
  163. * @param [array] $scene 格式的参数
  164. * @param [string] $page 小程序路径
  165. * @return void
  166. */
  167. public function MiniProgramQrCode(array $scene, $page, $name){
  168. $filepath = PATH_RES.'qrcode/';
  169. $response = WechatProgram::isTypes($this->miniapp_id)->app_code->getQrCode($page.'?'.http_build_query($scene));
  170. if ($response instanceof \EasyWeChat\Kernel\Http\StreamResponse) {
  171. $filename = $response->saveAs($filepath,md5($name));
  172. $path = '/' . str_replace('\\', '/', substr($filepath.$filename, strlen(PATH_PUBLIC)));
  173. return json(['code' => 200, 'msg' => '成功', 'data' => Request::root(true).$path]);
  174. }
  175. return enjson(404,'您的应用未上线');
  176. }
  177. /**
  178. * 禁止用户登录
  179. */
  180. protected function isUserAuth($code = 401){
  181. if(!$this->user){
  182. exit(json_encode(['code' => $code,'msg'=>'用户认证失败']));
  183. }
  184. }
  185. /**
  186. * 接口验证
  187. * @param mixed $var 签名验证的参数
  188. * @return array
  189. */
  190. protected function apiSign($var = [],$signType = 'md5'){
  191. $sign = Request::param('sign/s'); //获取签名
  192. $publickey = Request::param('publickey/s'); //获取公钥
  193. if(empty($sign)){
  194. $code = 401;
  195. $msg = '没有验证签名';
  196. }else{
  197. $secret = $this->miniapp->service_id;
  198. if(empty($publickey) && empty($secret)){
  199. $code = 403;
  200. $msg = '签名秘钥或公钥错误';
  201. }else{
  202. $var['sign'] = $sign;
  203. $var['publickey'] = $publickey;
  204. $sign = Sign::makeSign($var,$secret,$signType);
  205. if($var['sign'] == $sign){
  206. $code = 200;
  207. $msg = '成功';
  208. }else{
  209. $code = 403;
  210. $msg = '参数验证失败';
  211. }
  212. }
  213. }
  214. if($code != 200){
  215. exit(json_encode(['code' => $code,'msg' => $msg]));
  216. }
  217. return ['code' => $code,'msg' => $msg];
  218. }
  219. /**
  220. * 接口验证
  221. * @param mixed $var 签名验证的参数
  222. * @return array
  223. */
  224. protected function makeSign($var = [],$secret = null,$signType = 'md5'){
  225. if(empty($secret)){
  226. $secret = $this->miniapp->service_id;
  227. }
  228. $var['sign'] = Sign::makeSign($var,$secret,$signType);
  229. return $var;
  230. }
  231. /**
  232. * 如果增加双向验证请在这里增加
  233. * 增加服务器登录安全认证
  234. * @return void
  235. */
  236. protected function getUser(){
  237. $rel = WechatProgram::checkToken(['service_id' => $this->miniapp->service_id,'token'=>$this->token]);
  238. if($rel){
  239. return SystemUser::where(['id' => $rel['uid'],'is_lock' => 0])->find();
  240. }
  241. return;
  242. }
  243. }