input('channel_mark')); // 渠道标识 $gameid = strtolower($this->input('gameid')); // 游戏id $channelModel = new ComplexChannelModel; if (!($channel_id = $channelModel->where(['status' => 1, 'mark' => $prefix])->value('id'))) { $this->jsonResult('', -201, '渠道信息不存在'); } if (!$polyChannelGame = (new PolychannelGame())->alias('cpg')->join('cy_game cg', 'cpg.game_id=cg.id')->field('cpg.*, cg.type as game_type')->where(['cpg.channel_id' => $channel_id, 'cpg.game_id' => $gameid])->find()) { $this->jsonResult('', -202, '渠道游戏不存在.'); } // 判断是否有做登录验证的渠道 if (in_array($prefix, $this->_neekCheckChannel)) { try { $sentence = ucfirst($prefix); $className = 'app\api\complex\\' . $sentence; $model = new $className; // H5 渠道游戏,单独处理 if(in_array($prefix, $this->h5_handle_channel) && $polyChannelGame['game_type'] == 3){ $result = $model->getSpecialParamH5($this->input, $polyChannelGame); }else{ $result = $model->getSpecialParam($this->input, $polyChannelGame); } if ($result) { // 渠道效验判断,针对部分渠道的后台配置qmKey需要 if (!empty($polyChannelGame['param']) && $this->input('device') == '2') { if ($paramArr = json_decode($polyChannelGame['param'], true)) { $qmKey = $this->input('qmKey'); // 游戏id if (isset($paramArr['qmKey'])) { if ($paramArr['qmKey'] != $qmKey || empty($qmKey)) { curlDD("渠道 " . $sentence . '@用户账号: ' . $result . ' 破解Android加固!', Env::get('dingtalk.warning_url')); $this->jsonResult('', -221, '当前渠道不可用!'); } } } } $this->jsonResult(['cuserid' => $result], 1, '获取成功'); } else { $msg = "登陆失效或二次验证失败"; // 优化提示判断 if(!empty($result['code']) && $result['code'] < 0){ $msg .= ", (c_err:{$result['code']})"; } $this->jsonResult('', -222, $msg); } } catch (Exception $e) { log_message("渠道-" . $sentence . '-二次效验失败:' . $e->getCode() . ":" . $e->getMessage() . '; ' . $e->getFile() . ':' . $e->getLine(), 'error', LOG_PATH . "complexLoginlog/{$prefix}/"); curlDD("渠道-" . $sentence . '-二次效验失败:'. $e->getCode() . ":" . $e->getMessage() . '; ' . $e->getFile() . ':' . $e->getLine(), Env::get('dingtalk.notic_url')); $this->jsonResult('', -233, '二次登录验证失败'); } } else { $this->jsonResult('', 0, '渠道未开启效验'); } } // 登录 public function index() { $channelModel = new ComplexChannelModel; $complexMembersModel = new ComplexMembers; $complexLogic = new Complex; $prefix = strtolower($this->input('channel_mark')); // 渠道标识 $complex_username = trim($this->input('username')); // 聚合用户名 $imeil = $this->input('imeil'); // 手机imeil码 $device = $this->input('device'); // 注册设备来源,1为PC,2为安卓,3为苹果 $gameid = $this->input('gameid'); // 游戏ID // $channelToken = $this->input('channelToken'); $userId = $this->input('user_id', ''); // 渠道效验接口 返回的ID if (!($channel_id = $channelModel->where(['status' => 1, 'mark' => $prefix])->value('id'))) { $this->jsonResult('', -120, '渠道信息不存在'); } if (!$polyChannelGame = (new PolychannelGame())->alias('cpg')->join('cy_game cg', 'cpg.game_id=cg.id')->field('cpg.*, cg.type as game_type')->where(['cpg.channel_id' => $channel_id, 'cpg.game_id' => $gameid])->find()) { $this->jsonResult('', -121, '渠道游戏不存在.'); } //游戏ID不能为空 if (empty($gameid)) { $this->jsonResult('', -122, '游戏ID不能为空'); } //游戏ID不能为空 if (empty($device)) { $this->jsonResult('', -123, '设备类型不能为空'); } // ## IOS 加固效验 if (!empty($polyChannelGame['param']) && $this->input('device') == '3' && !empty($this->input('qmversion'))) { $param = json_decode($polyChannelGame['param'], true); if (!empty($param['jg_key'])) { $jg_key = $this->input('jg_key'); //IOS 加固参数 if (empty($jg_key)) { $this->jsonResult('{}', 126, '当前渠道不可用!'); } $username = $this->input('username'); // username $rsa_res = (new RsaSign())->openssl_private_decrypt($jg_key); $ios_sign_key = $param['jg_key'] . $userId; if ($ios_sign_key !== $rsa_res) { curlDD("渠道 " . $prefix . '@聚合账户: ' . $username . ' 破解IOS加固!', Env::get('dingtalk.warning_url')); $this->jsonResult('{}', 126, '当前渠道不可用!'); } } } // ## 渠道登录效验 $result = []; if (in_array($prefix, $this->_neekCheckChannel)) { // $paramArr = [ // 'username' => trim($this->input('username')) , // 'imeil' => $this->input('imeil') , // 'device' => $this->input('device') , // 'gameid' => $this->input('gameid') , // 'channel_mark' => strtolower($this->input('channel_mark')) , // 'channelToken' => $this->input('channelToken') , // ]; try { $sentence = ucfirst($prefix); $className = 'app\api\complex\\' . $sentence; $model = new $className; // H5 渠道游戏,单独处理 if(in_array($prefix, $this->h5_handle_channel) && $polyChannelGame['game_type'] == 3){ $result = $model->checkLoginH5($this->input, $polyChannelGame); }else{ $result = $model->checkLogin($this->input, $polyChannelGame); } // 默认判断 if (!$result) { $this->jsonResult('', -131, "登录验证失败"); } // 优化提示判断 if(!empty($result['code']) && $result['code'] < 0){ $msg = "登录验证失败, (c_err:{$result['code']})"; $this->jsonResult('', -132, $msg); } // 检查是否有 setParam 方法 if (method_exists($model, 'setParam')) { $this->_extparam = $model->setParam($this->input); } } catch (Exception $e) { log_message("渠道-" . $sentence . '-登陆效验失败:' . $e->getCode() . ":" . $e->getMessage() . '; ' . $e->getFile() . ':' . $e->getLine(), 'error', LOG_PATH . "complexLoginlog/{$prefix}/"); curlDD("渠道-" . $sentence . '-登陆效验失败-渠道登录回调:msg=' . $e->getMessage() .' - input:'. json_encode($this->input), Env::get('dingtalk.notic_url')); $this->jsonResult('', -130, '登录验证异常.'); } // $className = 'app\api\controller\complex\\' . $sentence.'Login'; // $model_c = new $className; // $model_c->setParam($paramArr); // $resArr = $model_c->indexcheck(); // log_message('xmw--get_http_response()--7-END--'.json_encode($resArr),'log',LOG_PATH . 'complexLoginlog/'); // // 判断是否验证成功 // if (!$resArr['code']){ // $this->jsonResult('',0,$resArr['msg']); // } // $this->_extparam = $resArr['extparam']; // // 参数重置 // log_message('xmw--get_http_response()--7.5-END--'.count($resArr['data']),'log',LOG_PATH . 'complexLoginlog/'); // if (count($resArr['data'])){ // log_message('xmw--get_http_response()--8-END--'.count($resArr['data']),'log',LOG_PATH . 'complexLoginlog/'); // foreach ($resArr['data'] as $k=>$v){ // log_message('xmw--get_http_response()--9-END--'.$k.'----'.$v,'log',LOG_PATH . 'complexLoginlog/'); // $this->setInput($k,$v); // } // unset($v); // } } if (empty($complex_username)) { $this->jsonResult('', -140, '用户名不能为空'); } if (empty($imeil)) { $this->jsonResult('', -141, '设备imeil异常'); } if (empty($prefix)) { $this->jsonResult('', -142, '渠道标识不能为空'); } if ($complexLogic->isFrozen($channel_id, $gameid, 'login')) { //根据预付款进行登录冻结判断还未加 $this->jsonResult('', -143, '您所在渠道已经被禁止登录此游戏'); } elseif (in_array($prefix, Config::get('complex_disable_login')['channel_mark']) && in_array($gameid, Config::get('complex_disable_login')['game_id'])) { //特殊的渠道和游戏禁止登录 $this->jsonResult('', -144, '您所在渠道已经被禁止登录此游戏'); } // 启动事务 Db::startTrans(); try { //nw_complex_members表中用户信息 $userinfo = $complexMembersModel->where(['complex_username' => $complex_username, 'channel_id' => $channel_id, 'gameid' => $gameid])->find(); //用户信息已存在,登录 if (!empty($userinfo)) { $loginInfo = $this->loginProcess($userinfo, $gameid, $imeil, $device, $channel_id); $memberSaveData = ['login_time' => NOW_TIMESTAMP]; if ($userId) { $memberSaveData['complex_id'] = $userId; } if (!empty($this->_extparam)) { $memberSaveData['extparam'] = json_encode($this->_extparam); } //更新最后登录时间 $complexMembersModel->update($memberSaveData, ['id' => $userinfo['id']]); $mg_username = $userinfo['mg_username']; // 我方用户名 } //用户信息不存在,注册 else { //根据预付款进行注册冻结判断还未加 if ($complexLogic->isFrozen($channel_id, $gameid, 'register')) { throw new Exception("您所在渠道已经被禁止注册此游戏"); } $memberData = [ 'complex_username' => $complex_username, 'device' => $device, 'gameid' => $gameid, 'imei' => $imeil, 'channel_id' => $channel_id, 'reg_time' => NOW_TIMESTAMP, 'login_time' => NOW_TIMESTAMP, 'ip' => request()->ip() ]; if ($userId) { $memberData['complex_id'] = $userId; } if (!empty($this->_extparam)) { $memberData['extparam'] = json_encode($this->_extparam); } $userinfo = $complexMembersModel->create($memberData); // ## 游戏支持双端互通 $pre_uid = $userinfo['id']; if(!empty($result['user_id'])){ $pre_uid = $result['user_id']; } $mg_username = $prefix . '___' . $pre_uid . 'z'; // 我方用户名 $complexMembersModel->update(['mg_username' => $mg_username], ['id' => $userinfo['id']]); $memberData['id'] = $userinfo['id']; $memberData['mg_username'] = $mg_username; $loginInfo = $this->loginProcess($memberData, $gameid, $imeil, $device, $channel_id); } $sign_str = "username={$mg_username}&appkey=" . $this->appInfo['appkey'] . "&logintime=" . NOW_TIMESTAMP; $sign = md5($sign_str); //这个暂时好像没什么用,只是参考旧SDK的 // 提交事务 Db::commit(); } catch (\Exception $e) { // 回滚事务 Db::rollback(); $this->jsonResult('', -110, '登录失败! ' . $e->getMessage()); } $result = [ 'user_id' => (string)$userinfo['id'], 'username' => $mg_username, 'token' => $loginInfo['token'], 'logintime' => NOW_TIMESTAMP, 'sign' => $sign, 'extparam' => $this->_extparam ]; if (isset($loginInfo['jwt_token'])) { $result['jwt_token'] = $loginInfo['jwt_token']; } $this->jsonResult($result, 1, '登录成功'); exit; } /** * 用户登录公共部分处理 * * @param $userinfo : array 用户信息数组 * @param $gameid : int 游戏ID * @param $imeil : string 手机imei码 * @param $device : int 注册设备来源 * @param $channelId : int 当前登录的渠道ID * * @return $token: string 用户登录token */ private function loginProcess($userinfo, $gameid, $imeil, $device, $channelId) { $loginlogModel = new ComplexLoginlog(); $logData['userid'] = $userinfo['id']; $logData['gameid'] = $gameid; $logData['imei'] = $imeil; $logData['channel_id'] = $channelId; $logData['login_time'] = NOW_TIMESTAMP; $logData['ip'] = request()->ip(); $loginlogModel->insert($logData); //token的随机码 $token_random = random(8); $loginFailureTime = 60 * 60 * 24 * 30; // 登录态 token 为登录标识 $token = auth_code($userinfo['id'] . '|' . $userinfo['mg_username'] . '|' . $gameid . '|' . $userinfo['mg_username'] . '|' . $token_random . '|cm', "ENCODE", Env::get('auth_key')); // $imeil 做为唯一登录标识 Cache::store('default')->set($token, $imeil, $loginFailureTime); //redis中玩家登录安全控制的随机码 Cache::store('default')->set('token|cm|' . $userinfo['id'] . '|' . $gameid, $token_random, $loginFailureTime); $returnData = ['token' => $token]; // ## JWT:仅版本号大于 v3.6.8 的客户端返回 ## if (!empty($this->version) && version_compare($this->version, '3.6.8', '>')) { $jwtKey = trim((string) Env::get('jwt.jwt_key', '')); $jwtExpTime = (int) $loginFailureTime; $returnData['jwt_token'] = ''; if ($jwtKey === '' || $jwtExpTime <= 0) { trace('JWT配置缺失或错误,请检查jwt.jwt_key', 'error'); } else { $jwtIssuedAt = time(); $jwtUserData = [ 'member_id' => $userinfo['id'], 'mg_username' => $userinfo['mg_username'], 'game_id' => $gameid, 'complex_id' => $channelId, 'iat' => $jwtIssuedAt, 'exp' => $jwtIssuedAt + $jwtExpTime, ]; $returnData['jwt_token'] = JwtToken::encode($jwtUserData, $jwtKey); } } return $returnData; } /** * 获取游戏配置参数(有些游戏有多个参数时需要特殊处理) * @param $game_id 游戏id * @param $channel_mark 渠道标识 * @param string $data 返回的数据 * @param string $code 返回的code * @param string $msg 返回的msg * @return mixed */ // public function getGameParam($game_id,$channel_mark,$data='',$code='0',$msg='该游戏的验签参数还未设置'){ // $polyChannelGameModel = new PolychannelGame; // $param = $polyChannelGameModel->alias('a') // ->join('nw_channel b','b.id = a.channel_id') // ->where(['a.game_id'=>$game_id,'b.mark'=>$channel_mark]) // ->value('a.param'); // // if(empty($param)){ // log_message('后台渠道游戏中,用于该游戏的验签参数还未设置,game_id='.$game_id.',渠道标识='.$channel_mark,'error',LOG_PATH . '../complexPaylog/'); // // $this->jsonResult($data,$code,$msg); // } // // $param = unserialize($param); // return $param; // } /** * 获取游戏指定的用户名连接符 * * @param int $gameid 游戏ID * @return string */ // public function get_username_connector($gameid) { // $specify = ['116','173','201']; // // if ( in_array($gameid, $specify) ) { // return '#'; // } else { // return '___'; // } // } }