Преглед на файлове

服务端支持简单登录,支持小程序不用用户认证,静默登录

joe преди 4 години
родител
ревизия
02c345ee55
променени са 3 файла, в които са добавени 181 реда и са изтрити 3 реда
  1. 164 3
      app/api/controller/wechat/AuthController.php
  2. 14 0
      app/api/controller/wechat/WechatController.php
  3. 3 0
      route/api/route.php

+ 164 - 3
app/api/controller/wechat/AuthController.php

@@ -10,11 +10,13 @@ use crmeb\services\CacheService;
 use crmeb\services\MiniProgramService;
 use crmeb\services\UtilService;
 use app\models\user\UserToken;
-use crmeb\services\SystemConfigService;
 use app\models\user\User;
-use app\models\routine\RoutineFormId;
 use think\facade\Cache;
 use crmeb\services\SubscribeTemplateService;
+use crmeb\services\template\storage\Wechat;
+use EasyWeChat\MiniProgram\MiniProgram;
+use think\facade\Log;
+use tw\redis\UserRds;
 
 /**
  * 小程序相关
@@ -24,6 +26,159 @@ use crmeb\services\SubscribeTemplateService;
 class AuthController
 {
 
+    /**
+     * tw 新增函數, 小程序登錄
+     * 過程: 小程序中運行 wx.login() 獲取 code, 然後調用 mp_auth_login
+     * mp_auth_login 執行
+     * 1. 從 code 解析出 openId, 根據 openId 檢查用戶,存在,則返回 token,登录成功
+     * 2. 不存在該 openId, 則是新用戶,返回 失敗,需要小程序做 wx.getUserProfile 调用后,
+     *      然后调用 mp_auth_login_with_userinfo 接口, 注册或刷新用户信息后,返回登录成功协议
+     * 小程序調用成功,就登錄成功 (注意:此时有两个问题 1. 目前测试得不到 unionId; 
+     *      2. 此时用户微信资料如果变动,不会刷新)
+     * 小程序得到失败,就要求用户授权 wx.getUserProfile 获取微信资料,生成新的用户,返回 token, 相当与注册过程。
+     * 
+     * mp_auth_login 即使执行成功,过一段时间也要返回失败,使得小程序发起重新授权,刷新用户微信资料。
+     * 
+     * 返回字段:
+     * 
+     * 'token' => $token->token,
+     * 'userInfo' => $userInfo,
+     * 'expires_time' => strtotime($token->expires_time),
+     * 'cache_key' => $cache_key
+     * 以上兼容旧协议
+     * 'status' => 0/1 0 表示正常登录成功, 1 表示需要进一步调用 wx.getUserProfile 进行授权
+     */
+    public function mp_auth_simple(Request $request)
+    {
+        list($code) = UtilService::postMore([
+            ['code', ''],
+        ], $request, true);
+        Log::debug(__FUNCTION__ . " param code: $code");
+        try {
+            $json2sess = MiniProgramService::getUserInfo($code);
+            // $sess_key = $json2sess['session_key'] ?? '';
+            $openId = $json2sess['openid'] ?? '';
+            $unionid = $json2sess['unionid'] ?? '';
+            Log::debug("openid=$openId, unionid=$unionid");
+            // find by unionid
+            if ($unionid != '' ) {
+                $uid = WechatUser::where(['unionid' => $unionid])
+                    ->where('user_type', 'routine')->value('uid');
+            } else if ($openId != '') {
+                $uid = WechatUser::where(['routine_openid' => $openId])->where('user_type', 'routine')->value('uid');
+            }
+            Log::debug("uid=$uid");
+            if (!$uid) {
+                return app('json')->successful([
+                    'token' => '',
+                    'userInfo' => [],
+                    'expires_time' => 0,
+                    'cache_key' => '',
+                    'status' => 1,  // 需进一步
+                ]);
+            }
+            $user = User::get($uid);
+            if (!$user) {
+                return app('json')->successful([
+                    'token' => '',
+                    'userInfo' => [],
+                    'expires_time' => 0,
+                    'cache_key' => '',
+                    'status' => 1,  // 需进一步
+                ]);
+            }
+            $token = UserToken::createToken($user, 'routine');
+            if (!$token) {
+                return app('json')->fail('获取用户访问token失败!');
+            }
+            Log::debug("token=" . $token->token);
+            // 缓存 session_key
+            $cache_key = md5(time() . $code);
+            Cache::set('eb_api_code_' . $cache_key, $json2sess, SECONDS_OF_ONEDAY);
+            // 获取用户上次刷新时间,距今超过 2 周就刷新
+            $ur = new UserRds();
+            $last = $ur->get($uid, 'last_refresh');
+            if (time() - intval($last) >= SECONDS_OF_ONEDAY * 15) {
+                return app('json')->successful([
+                    'token' => '',
+                    'userInfo' => [],
+                    'expires_time' => 0,
+                    'cache_key' => '',
+                    'status' => 1,  // 需进一步
+                ]);
+            }
+            // 返回登录成功
+            event('UserLogin', [$user, $token]);
+            return app('json')->successful([
+                'token' => $token->token,
+                'userInfo' => $user->toArray(),
+                'expires_time' => strtotime($token->expires_time),
+                'cache_key' => $cache_key,
+                'status' => 1,  // 登录成功
+            ]);
+        } catch (\Exception $e) {
+            Log::error(__FUNCTION__ . 'exception:' . $e->getMessage());
+            return app('json')->fail('获取session_key失败');
+        }
+    }
+
+    /**
+     * @deprecated
+     * 小程序在 mp_auth_login 返回特定值(表示用户不存在,或刷新用户信息)后,
+     * 调用 wx.getUserProfile 获取用户信息,来注册或刷新信息。
+     */
+    public function mp_auth_with_userinfo(Request $request)
+    {
+        list($cache_key, $spread_spid, $spread_code, $iv, $encryptedData, $login_type) = UtilService::postMore([
+            ['cache_key', ''],
+            ['spread_spid', 0],
+            ['spread_code', ''],
+            ['iv', ''],
+            ['encryptedData', ''],
+            ['login_type', ''],
+        ], $request, true);
+
+        // 获取缓存 openId, sessionKey
+        $json2sess = Cache::get('eb_api_code_' . $cache_key);
+        if (!$json2sess) {
+            return app('json')->fail('访问超时');
+        }
+        // 解密用户数据
+        try {
+            $userInfo = MiniProgramService::encryptor($json2sess['session_key'], $iv, $encryptedData);
+        } catch (\Exception $e) {
+            if ($e->getCode() == '-41003') return app('json')->fail('获取会话密匙失败');
+        }
+        if (!isset($userInfo['unionId'])) {
+            $userInfo['unionId'] = '';
+        }
+        // 新增或更新
+        $userInfo['openId'] = $json2sess['openid'];
+        $userInfo['spid'] = $spread_spid;
+        $userInfo['code'] = $spread_code;
+        $userInfo['session_key'] = $json2sess['session_key'];
+        $userInfo['login_type'] = $login_type;
+        $uid = WechatUser::routineOauth($userInfo);
+        $userInfo = User::where('uid', $uid)->find();
+        // 返回
+        if ($userInfo->login_type == 'h5' && ($h5UserInfo = User::where(['account' => $userInfo->phone, 'phone' => $userInfo->phone, 'user_type' => 'h5'])->find()))
+            $token = UserToken::createToken($userInfo, 'routine');
+        else
+            $token = UserToken::createToken($userInfo, 'routine');
+        if ($token) {
+            event('UserLogin', [$userInfo, $token]);
+            return app('json')->successful('登陆成功!', [
+                'token' => $token->token,
+                'userInfo' => $userInfo,
+                'expires_time' => strtotime($token->expires_time),
+                'cache_key' => $cache_key,
+                'status' => 0,
+            ]);
+        } else {
+            return app('json')->fail('获取用户访问token失败!');
+        }
+    }
+
     /**
      * 小程序授权登录
      * @param Request $request
@@ -41,6 +196,7 @@ class AuthController
             ['cache_key', ''],
             ['login_type', '']
         ], $request, true);
+        Log::debug("code=$code, post_cache_key=$post_cache_key, login_type=$login_type");
         $session_key = Cache::get('eb_api_code_' . $post_cache_key);
         if (!$code && !$session_key)
             return app('json')->fail('授权失败,参数有误');
@@ -55,6 +211,7 @@ class AuthController
                     errmsg	string	错误信息
                  */
                 $userInfoWx = MiniProgramService::getUserInfo($code);
+                Log::debug('userinfo=' . json_encode($userInfoWx));
                 $session_key = $userInfoWx['session_key'];
                 $cache_key = md5(time() . $code);
                 Cache::set('eb_api_code_' . $cache_key, $session_key, 86400);
@@ -72,6 +229,7 @@ class AuthController
         try {
             //解密获取用户信息
             $userInfo = MiniProgramService::encryptor($session_key, $data['iv'], $data['encryptedData']);
+            Log::debug('userinfo=' . json_encode($userInfo));
         } catch (\Exception $e) {
             if ($e->getCode() == '-41003') return app('json')->fail('获取会话密匙失败');
         }
@@ -92,14 +250,17 @@ class AuthController
             $token = UserToken::createToken($userInfo, 'routine');
         if ($token) {
             event('UserLogin', [$userInfo, $token]);
+            $ur = new UserRds();
+            $ur->set($uid, 'last_refresh', time());
             return app('json')->successful('登陆成功!', [
                 'token' => $token->token,
                 'userInfo' => $userInfo,
                 'expires_time' => strtotime($token->expires_time),
                 'cache_key' => $cache_key
             ]);
-        } else
+        } else {
             return app('json')->fail('获取用户访问token失败!');
+        }
     }
 
     /**

+ 14 - 0
app/api/controller/wechat/WechatController.php

@@ -99,6 +99,20 @@ class WechatController
             return app('json')->fail('登录失败');
     }
 
+    /**
+     * app 授权登陆
+     * @param Request $request
+     * @return mixed
+     * @throws \think\db\exception\DataNotFoundException
+     * @throws \think\db\exception\ModelNotFoundException
+     * @throws \think\exception\DbException
+     */
+    public function auth_app(Request $request)
+    {
+        // 见文档 帐号.md
+
+    }
+
     public function follow()
     {
         $canvas = Canvas::instance();

+ 3 - 0
route/api/route.php

@@ -233,8 +233,11 @@ Route::group(function () {
     //微信
     Route::get('wechat/config', 'wechat.WechatController/config')->name('wechatConfig');//微信 sdk 配置
     Route::get('wechat/auth', 'wechat.WechatController/auth')->name('wechatAuth');//微信授权
+    Route::get('wechat/auth_app', 'wechat.WechatController/auth_app')->name('wechatAuthApp'); // 微信APP授权
 
     //小程序登陆
+    Route::post('wechat/mp_auth_simple', 'wechat.AuthController/mp_auth_simple')->name('wechatAuthLogin'); // 只利用 code 登录
+    Route::post('wechat/mp_auth_with_userinfo', 'wechat.AuthController/mp_auth_with_userinfo')->name('wechatAuthWithUserinfo');// 提交用户资料注册或刷新
     Route::post('wechat/mp_auth', 'wechat.AuthController/mp_auth')->name('mpAuth');//小程序登陆
     Route::get('wechat/get_logo', 'wechat.AuthController/get_logo')->name('getLogo');//小程序登陆授权展示logo
     Route::post('wechat/set_form_id', 'wechat.AuthController/set_form_id')->name('setFormId');//小程序登陆收集form id