Просмотр исходного кода

feat(api): 添加小程序一键登录功能

- 新增 mpLogin 接口支持小程序一键登录
- 集成微信授权码换取 session_key 流程
- 实现手机号解密和验证功能
- 添加基于手机号的用户注册和登录逻辑
- 支持分享关系绑定和新用户标识返回
- 集成 WXBizDataCrypt 解密库处理加密数据
shichen месяцев назад: 2
Родитель
Сommit
101b31d176
2 измененных файлов с 82 добавлено и 0 удалено
  1. 80 0
      app/controller/api/user/UserMp.php
  2. 2 0
      route/api.php

+ 80 - 0
app/controller/api/user/UserMp.php

@@ -14,6 +14,7 @@ use app\common\dao\user\UnionUsersDao;
14 14
 use app\common\repositories\article\AgreementRepository;
15 15
 use app\common\repositories\merchant\order\OrderMerchantRepository;
16 16
 use app\common\repositories\user\UnionUsersRepository;
17
+use applet\WXBizDataCrypt;
17 18
 use crmeb\basic\BaseController;
18 19
 use app\common\repositories\user\UserRepository;
19 20
 use crmeb\services\MiniProgramService;
@@ -67,6 +68,85 @@ class UserMp extends BaseController
67 68
         return app('json')->success($get);
68 69
     }
69 70
 
71
+    /**
72
+     * 小程序一键登录(合并 getUserUnionid + applet_phone)
73
+     * 接收 code、encryptedData、iv,内部调用微信接口获取 session_key,解密手机号后注册/登录
74
+     * @param UserRepository $repository
75
+     * @return \think\response\Json
76
+     */
77
+    public function mpLogin(UserRepository $repository)
78
+    {
79
+        try {
80
+            $data = $this->request->params(['code', 'encryptedData', 'iv', 'share_id', 'source']);
81
+            if (!$data['code'] || $data['code'] == '' || $data['code'] == 'undefined') {
82
+                return app('json')->fail('code参数缺失');
83
+            }
84
+            if (!$data['encryptedData'] || $data['encryptedData'] == '') {
85
+                return app('json')->fail('encryptedData参数缺失');
86
+            }
87
+            if (!$data['iv'] || $data['iv'] == '') {
88
+                return app('json')->fail('iv参数缺失');
89
+            }
90
+
91
+            $appid = 'wx9082e5ac2fdb513f';
92
+            $secret = 'e334c41e1c4aa962f65d1882092fbda6';
93
+
94
+            // 1. 调用微信 jscode2session 接口获取 session_key
95
+            $url = "https://api.weixin.qq.com/sns/jscode2session?appid=" . $appid . "&secret=" . $secret . "&js_code=" . $data['code'] . "&grant_type=authorization_code";
96
+            $wxResult = curlGet($url);
97
+            if (!$wxResult || !isset($wxResult['session_key'])) {
98
+                Log::error('mpLogin jscode2session失败: ' . json_encode($wxResult));
99
+                return app('json')->fail('微信登录凭证校验失败');
100
+            }
101
+            $sessionKey = $wxResult['session_key'];
102
+
103
+            // 2. 解密手机号
104
+            $sessionKey = str_replace(' ', '+', $sessionKey);
105
+            $encryptedData = str_replace(' ', '+', $data['encryptedData']);
106
+            $iv = str_replace(' ', '+', $data['iv']);
107
+
108
+            $pc = new WXBizDataCrypt($appid, $sessionKey);
109
+            $errCode = $pc->decryptData($encryptedData, $iv, $decryptData);
110
+            if ($errCode != 0) {
111
+                return app('json')->fail('手机号解密失败');
112
+            }
113
+            $decryptData = json_decode($decryptData, true);
114
+            $phone = $decryptData['purePhoneNumber'] ?? '';
115
+            if ($phone == '') {
116
+                return app('json')->fail('未获取到手机号');
117
+            }
118
+            if (!preg_match("/^1[3456789]{1}\d{9}$/", $phone) && !preg_match("/^[569]\d{7}$/", $phone)) {
119
+                return app('json')->fail('手机号格式错误');
120
+            }
121
+
122
+            // 3. 注册或登录
123
+            $userRes = Db::name('user')->where('account', $phone)->find();
124
+            $isnew = false;
125
+            if (!$userRes) {
126
+                $spreadUid = 0;
127
+                if (!empty($data['share_id'])) {
128
+                    $spreadUid = Db::name('product_share')->where('id', $data['share_id'])->value('uid');
129
+                    if (!intval($spreadUid)) {
130
+                        $spreadUid = 0;
131
+                    }
132
+                }
133
+                $repository->registr($phone, 123456, 'APP', '', '', '', $spreadUid);
134
+                $isnew = true;
135
+            }
136
+
137
+            $user = $repository->accountByUser($phone);
138
+            $user = $repository->mainUser($user);
139
+            $tokenInfo = $repository->createToken($user);
140
+            $repository->loginAfter($user);
141
+
142
+            return app('json')->success(array_merge($repository->returnToken($user, $tokenInfo), ['is_new' => $isnew ? 1 : 0]));
143
+
144
+        } catch (\Exception $e) {
145
+            Db::name('log')->insert(['data' => 'mpLogin出错:' . $e->getFile() . ':' . $e->getLine() . '【' . $e->getMessage() . '】']);
146
+            return app('json')->fail('登录失败');
147
+        }
148
+    }
149
+
70 150
     public function getPhoneToBind(){
71 151
 
72 152
         $data = $this->request->params([

+ 2 - 0
route/api.php

@@ -1199,6 +1199,8 @@ Route::group('api/', function () {
1199 1199
     Route::post('userMp/getUserUnionid','api.user.UserMp/getUserUnionid');
1200 1200
     //小程序获取用户手机号码并绑定
1201 1201
     Route::post('userMp/getPhoneToBind','api.user.UserMp/getPhoneToBind');
1202
+    //小程序一键登录(合并 getUserUnionid + applet_phone)
1203
+    Route::post('userMp/mpLogin','api.user.UserMp/mpLogin');
1202 1204
 
1203 1205
     //小程序支付
1204 1206
     Route::post('mpPay/jsapiPay','api.store.order.MpOrder/jsapiPay');