AuthLogic.php 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529
  1. <?php
  2. namespace addons\RealAuth\common\logic;
  3. use common\enums\AddonsEnum;
  4. use common\traits\ErrorTrait;
  5. use common\enums\StatusEnum;
  6. use common\models\mall\MallAddons;
  7. use Yii;
  8. use Exception;
  9. use addons\RealAuth\common\models\RealAuthUser;
  10. use addons\RealAuth\common\models\RealAuthDetail;
  11. use addons\RealAuth\common\events\RealAuthEvent;
  12. /**
  13. * 实名认证逻辑类
  14. * User: zmz
  15. * Date: 2022/5/20
  16. * Time: 13:14
  17. */
  18. class AuthLogic
  19. {
  20. use ErrorTrait;
  21. const CODE_SUCCESS = 0; //调用成功状态码
  22. //实名认证接口地址
  23. public $host = 'https://service-18c38npd-1300755093.ap-beijing.apigateway.myqcloud.com/release/idcard/VerifyIdcardv2';
  24. private $newHost = 'https://ap-beijing.cloudmarket-apigw.com/service-18c38npd/idcard/VerifyIdcardv2';
  25. /**
  26. * 姓名+身份证进行 实名认证
  27. * @param $user_id
  28. * @param $real_name
  29. * @param $id_no
  30. * @param int $mall_id
  31. * @return mixed
  32. * @throws Exception
  33. */
  34. public function auth($params)
  35. {
  36. $user_id = $params['user_id'];
  37. $mall_id = $params['mall_id'];
  38. $real_name = $params['real_name'];
  39. $id_no = $params['id_no'];
  40. $check_pass_mode = $params['check_pass_mode'] ?? 0; // 检查是否验证通过逻辑 0原逻辑:根据userid确认是否实名 1根据userid+姓名+身份证号码作为条件查询
  41. $business_code = isset($params['detail']['business_code']) ? $params['detail']['business_code'] : '';
  42. if(empty($params['auth_type'])){
  43. $params['auth_type'] = RealAuthUser::USER;
  44. }
  45. if(empty($real_name)){
  46. throw new Exception('请输入姓名');
  47. }
  48. if(empty($id_no)){
  49. throw new Exception('请输入身份证号码');
  50. }
  51. if(isset($params['detail']) && !is_array($params['detail'])){
  52. $params['detail'] = json_decode($params['detail'],true);
  53. }
  54. $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  55. if(!isset($config['status']) || !$config['status']){
  56. throw new Exception('尚未开启实名认证功能');
  57. }
  58. // 云市场分配的密钥Id , 云市场分配的密钥Key
  59. if(empty($config['secret_id']) || empty($config['secret_key'])){
  60. throw new Exception('实名认证配置错误');
  61. }
  62. if ($check_pass_mode == 1) {
  63. $auth_user = RealAuthUser::getUserByInfo($mall_id,$user_id, $real_name, $id_no);
  64. } else {
  65. $auth_user = RealAuthUser::getUser($mall_id,$user_id);
  66. }
  67. if($auth_user && $auth_user->auth && $auth_user->auth_type == $params['auth_type']){
  68. throw new Exception('您已通过实名认证');
  69. }
  70. //企业验证设置
  71. if(!empty($config['setting_status']) && $auth_user && $auth_user->auth_type != $params['auth_type']){
  72. throw new Exception('不能同时认证企业和个人账户');
  73. }
  74. if($config['id_no_limit'] && $params['auth_type'] == RealAuthUser::USER){
  75. //1个证件号码只能用于1个会员
  76. $flag = true;
  77. $id_no_exist = RealAuthUser::find()->where(['mall_id' => $mall_id,'id_no' => $id_no, 'auth' => 1,'auth_type'=>$params['auth_type']])->select('id')->column();
  78. if(!empty($id_no_exist)){
  79. $flag = false;
  80. }
  81. if(!$flag){
  82. throw new Exception('该身份证号码已存在认证');
  83. }
  84. }
  85. if($config['upgrade_status'] && $params['auth_type'] == RealAuthUser::BUSINESS){
  86. //1个营业执照号只能用于1个会员
  87. $flag = true;
  88. $id_no_exist = RealAuthUser::find()
  89. ->where(['mall_id' => $mall_id,'business_code' => $business_code])
  90. ->andWhere(['!=','user_id',$user_id])
  91. ->select('id')->column();
  92. if(!empty($id_no_exist)){
  93. $flag = false;
  94. }
  95. if(!$flag){
  96. throw new Exception('该营业执照号码已存在认证');
  97. }
  98. }
  99. $result = $this->sendAuthRequest($config, $real_name, $id_no);
  100. if(!isset($result['error_code']) || $result['error_code'] !== self::CODE_SUCCESS){
  101. throw new Exception('实名认证失败');
  102. }
  103. if(empty($result['result']['isok'])){
  104. return false;
  105. }
  106. // $data = '{"error_code":0,"reason":"成功","result":{"realname":"甘**","idcard":"450422************","isok":true,"IdCardInfor":{"province":"广西壮族自治区","city":"梧州市","district":"藤县","area":"广西壮族自治区梧州市藤县","sex":"男","birthday":"1996-8-2"}},"sn":"0303171859282651960407737232"}';
  107. // $result = json_decode($data,true);
  108. //认证通过才存表, isok = true , 认证通过
  109. //企业认证 需要后台审核实名状态才会更改为认证通过
  110. if(!empty($result['result']['isok'])){
  111. $t = \Yii::$app->db->beginTransaction();
  112. try{
  113. $auth_data = [
  114. 'id' => $auth_user && empty($auth_user->auth) ? $auth_user->id : 0,
  115. 'mall_id' => $mall_id,
  116. 'user_id' => $user_id,
  117. 'real_name' => $real_name,
  118. 'id_no' => $id_no,
  119. 'id_type' => 1,
  120. 'auth_result' => json_encode($result),
  121. 'auth' => $params['auth_type'] == RealAuthUser::BUSINESS ? 0 : 1,
  122. 'auth_type' => $params['auth_type'],
  123. 'business_code' => (string)$business_code,
  124. ];
  125. $real_auth_user_id = RealAuthUser::setData($auth_data);
  126. if(!$real_auth_user_id){
  127. throw new Exception('实名认证失败');
  128. }
  129. $detail_arr = [
  130. 'mall_id' => $mall_id,
  131. 'user_id' => $user_id,
  132. 'auth_type' => $params['auth_type'],
  133. 'auth_id' => $real_auth_user_id,
  134. 'detail' => $params['detail'] ?? [],
  135. 'check_status' => 0,
  136. ];
  137. $real_auth_detail = RealAuthDetail::setData($detail_arr);
  138. if(!$real_auth_detail){
  139. throw new Exception('实名认证失败');
  140. }
  141. $t->commit();
  142. }catch(\Exception $e){
  143. $t->rollBack();
  144. throw new \Exception($e->getMessage());
  145. }
  146. }
  147. //实名认证成功触发事务
  148. $event = new RealAuthEvent($mall_id);
  149. $data = [
  150. 'mall_id' => $mall_id,
  151. 'user_id' => $user_id,
  152. ];
  153. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  154. // return $result['result']['isok'];
  155. if($params['auth_type'] == RealAuthUser::BUSINESS){
  156. $msg = '企业信息已提交,工作人员将于'.$config['business_verify_time'].'小时内完成审核';
  157. }else{
  158. $msg = '实名认证成功';
  159. }
  160. return $msg;
  161. }
  162. /**
  163. * 实名认证请求
  164. * @param $config
  165. * @param $real_name
  166. * @param $id_no
  167. * @return mixed
  168. * @throws Exception
  169. */
  170. protected function sendAuthRequest($config, $real_name, $id_no)
  171. {
  172. $source = 'market';
  173. $datetime = gmdate('D, d M Y H:i:s T');
  174. $signStr = sprintf("x-date: %s\nx-source: %s", $datetime, $source);
  175. $sign = base64_encode(hash_hmac('sha1', $signStr, $config['secret_key'], true));
  176. $auth = sprintf('hmac id="%s", algorithm="hmac-sha1", headers="x-date x-source", signature="%s"', $config['secret_id'], $sign);
  177. $headers = [
  178. 'X-Source' => $source,
  179. 'X-Date' => $datetime,
  180. 'Authorization' => $auth,
  181. ];
  182. $queryParams = ['cardNo' => $id_no, 'realName' => $real_name];
  183. $url = $this->host . '?' . http_build_query($queryParams);
  184. if ($config['version'] == 1) {
  185. $signStr = sprintf("x-date: %s", $datetime);
  186. $sign = base64_encode(hash_hmac('sha1', $signStr, $config['secret_key'], true));
  187. $auth = sprintf('{"id": "%s", "x-date": "%s" , "signature": "%s"}', $config['secret_id'], $datetime, $sign);
  188. $headers = ['Authorization' => $auth];
  189. $url = $this->newHost . '?' . http_build_query($queryParams);
  190. }
  191. $ch = curl_init();
  192. curl_setopt($ch, CURLOPT_URL, $url);
  193. curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  194. curl_setopt($ch, CURLOPT_TIMEOUT, 60);
  195. curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'GET');
  196. curl_setopt($ch, CURLOPT_HTTPHEADER, array_map(function ($v, $k) {
  197. return $k . ': ' . $v;
  198. }, array_values($headers), array_keys($headers)));
  199. $data = curl_exec($ch);
  200. if (curl_errno($ch)) {
  201. Yii::error('实名认证接口Error:' . curl_error($ch) . ' | URL: ' . $url);
  202. throw new Exception('实名认证系统异常');
  203. }
  204. curl_close($ch);
  205. return json_decode($data, true);
  206. }
  207. /**
  208. * 个人认证升级企业认证
  209. * @param $params
  210. * @return bool|void
  211. */
  212. public function authUpgrade($params){
  213. $t = \Yii::$app->db->beginTransaction();
  214. try{
  215. $user_id = $params['user_id'];
  216. $mall_id = $params['mall_id'];
  217. $real_name = $params['real_name'];
  218. $id_no = $params['id_no'];
  219. $business_code = isset($params['detail']['business_code']) ? $params['detail']['business_code'] : '';
  220. if(empty($real_name)){
  221. throw new Exception('请输入姓名');
  222. }
  223. if(empty($id_no)){
  224. throw new Exception('请输入身份证号码');
  225. }
  226. if(!is_array($params['detail'])){
  227. $params['detail'] = json_decode($params['detail'],true);
  228. }
  229. $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  230. if(!isset($config['status']) || !$config['status']){
  231. throw new Exception('尚未开启实名认证功能');
  232. }
  233. // 云市场分配的密钥Id , 云市场分配的密钥Key
  234. if(empty($config['secret_id']) || empty($config['secret_key'])){
  235. throw new Exception('实名认证配置错误');
  236. }
  237. $auth = RealAuthUser::getUser($mall_id,$user_id);
  238. if(!$auth){
  239. throw new Exception('您未通过实名认证,无法申请升级为企业认证');
  240. }
  241. if($auth->auth && $auth->auth_type == RealAuthUser::BUSINESS){
  242. throw new Exception('您已通过企业实名认证');
  243. }
  244. if($config['upgrade_status']){
  245. //1个营业执照号只能用于1个会员
  246. $flag = true;
  247. $id_no_exist = RealAuthUser::find()
  248. ->where(['mall_id' => $mall_id,'business_code' => $business_code])
  249. ->andWhere(['!=','user_id',$user_id])
  250. ->select('id')->column();
  251. if(!empty($id_no_exist)){
  252. $flag = false;
  253. }
  254. if(!$flag){
  255. throw new Exception('该营业执照号码已存在认证');
  256. }
  257. }
  258. //一个身份证可有多个企业实名
  259. // $id_no_exist = RealAuthUser::find()
  260. // ->where(['mall_id' => $mall_id,'id_no' => $id_no, 'auth' => 1,'auth_type'=>RealAuthUser::BUSINESS])->one();
  261. // if($id_no_exist){
  262. // throw new Exception('该身份证号已存在企业认证');
  263. // }
  264. $detail_arr = [
  265. 'mall_id' => $mall_id,
  266. 'user_id' => $user_id,
  267. 'auth_type' => RealAuthUser::BUSINESS,
  268. 'auth_id' => $auth['id'],
  269. 'detail' => $params['detail'] ?? [],
  270. 'check_status' => 0,
  271. ];
  272. $real_auth_detail = RealAuthDetail::setData($detail_arr);
  273. if(!$real_auth_detail){
  274. throw new Exception('认证升级失败');
  275. }
  276. $auth = RealAuthUser::findOne(['id'=>$auth['id']]);
  277. $auth->business_code = (string)$business_code;
  278. if(!$auth->save()){
  279. throw new Exception('认证升级失败');
  280. }
  281. $t->commit();
  282. return true;
  283. }catch(\Exception $e){
  284. $t->rollBack();
  285. throw new \Exception($e->getMessage());
  286. }
  287. }
  288. /**
  289. * 检测当前应用场景是否需要实名认证
  290. * @param $params
  291. * @return bool|void
  292. */
  293. public function checkNeedAuth($params)
  294. {
  295. if (MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_REAL_AUTH) == 0) return false;
  296. $config = Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  297. if(!isset($config['status']) || !$config['status']){
  298. return false;
  299. }
  300. $config['scene'] = $config['scene'] ?? '';
  301. if(!$config['scene'] || strpos($config['scene'],$params['type']) === false){
  302. return false;
  303. }
  304. //查看应用场景
  305. $scene = explode(',',$config['scene']);
  306. if($params['type'] == 'order' && !in_array('order',$scene)){
  307. //下单
  308. if( in_array('part_order',$scene) && isset($params['goods_ids'])){
  309. if(!$config['goods_ids']) return false;
  310. //部分商品下单
  311. $config_goods_ids = json_decode($config['goods_ids']);
  312. //下单的商品不在后台设置范围
  313. if(!array_intersect($params['goods_ids'],$config_goods_ids)) return false;
  314. }
  315. }
  316. $auth = RealAuthUser::getUser($params['mall_id'],$params['user_id']);
  317. if($auth && $auth->auth){
  318. return false;
  319. }
  320. return true;
  321. }
  322. /**
  323. * 检测当前应用场景是否需要实名认证(企业)
  324. * @param $params
  325. * @return bool|void
  326. */
  327. public function checkNeedAuthBusiness($params)
  328. {
  329. if (MallAddons::isInstall($params['mall_id'], AddonsEnum::ADDONS_NAME_REAL_AUTH) == 0) return false;
  330. $config = Yii::$app->services->setting->addons->get($params['mall_id'], AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  331. if(!isset($config['setting_status']) || !$config['setting_status']){
  332. return false;
  333. }
  334. if(!isset($config['business_status']) || !$config['business_status']){
  335. return false;
  336. }
  337. //查看应用场景
  338. $scene = explode(',',$config['business_scene']);
  339. if(!$scene || !in_array($params['type'],$scene)){
  340. return false;
  341. }
  342. $auth = RealAuthUser::getUser($params['mall_id'],$params['user_id']);
  343. if($auth && $auth->auth && $auth->auth_type == RealAuthUser::BUSINESS){
  344. return false;
  345. }
  346. return true;
  347. }
  348. /**
  349. * 检测是否开启认证设置
  350. * @param $params
  351. * @return bool|void
  352. */
  353. public function getSetting($mall_id,$user_id = 0)
  354. {
  355. $result['setting_status'] = 0;
  356. $result['auth'] = 0;
  357. $result['auth_type'] = 0;
  358. if (MallAddons::isInstall($mall_id, AddonsEnum::ADDONS_NAME_REAL_AUTH) == 0){
  359. return $result;
  360. }
  361. $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  362. if(isset($config['setting_status'])){
  363. $result['setting_status'] = $config['setting_status'];
  364. }
  365. $auth = RealAuthUser::getUser($mall_id,$user_id);
  366. if($auth){
  367. $result['auth'] = $auth['auth'];
  368. $result['auth_type'] = $auth['auth_type'];
  369. }
  370. return $result;
  371. }
  372. /**
  373. * 企业认证审核
  374. * @param $params
  375. * @return bool|void
  376. */
  377. public function apply($params)
  378. {
  379. $t = \Yii::$app->db->beginTransaction();
  380. try{
  381. $real_auth_detail = RealAuthDetail::findOne(['id'=>$params['id']]);
  382. if(empty($real_auth_detail)){
  383. throw new \Exception('数据不存在');
  384. }
  385. $real_auth_detail->check_status = $params['status'];
  386. $real_auth_detail->check_at = time();
  387. $real_auth_detail->remark = $params['remark'];
  388. if(!$real_auth_detail->save()){
  389. throw new \Exception('数据更新异常');
  390. }
  391. if($params['status'] == 1){
  392. $auth = RealAuthUser::findOne(['id'=>$real_auth_detail->auth_id]);
  393. $auth->auth = 1;
  394. $auth->auth_type = RealAuthUser::BUSINESS;
  395. if(!$auth->save()){
  396. throw new \Exception('数据更新异常');
  397. }
  398. }
  399. $t->commit();
  400. if($params['status'] == 1){
  401. //实名认证成功触发事务
  402. $event = new RealAuthEvent($auth['mall_id']);
  403. $data = [
  404. 'mall_id' => $auth['mall_id'],
  405. 'user_id' => $auth['user_id'],
  406. ];
  407. \Yii::$app->services->events->dispatch($event, $data, $event->listeners);
  408. }
  409. }catch(\Exception $e){
  410. $t->rollBack();
  411. throw new \Exception($e->getMessage());
  412. }
  413. return true;
  414. }
  415. /**
  416. * 认证详情
  417. * @param $params
  418. * @return bool|void
  419. */
  420. public function getAuthDetail($mall_id,$user_id = 0)
  421. {
  422. $config = Yii::$app->services->setting->addons->get($mall_id, AddonsEnum::ADDONS_NAME_REAL_AUTH, 'basic');
  423. $result['business_no_limit'] = 0;
  424. $result['auth'] = 0;
  425. $result['auth_type'] = 0;
  426. //是否申请审核
  427. $result['is_apply'] = 0;
  428. //审核状态
  429. $result['check_status'] = 0;
  430. $result['remark'] = '';
  431. //是否申请实名升级
  432. $result['upgrade_status'] = 0;
  433. $result['info'] = [];
  434. $result['business_info'] = [];
  435. if(!empty($config['setting_status']) && !empty($config['business_no_limit'])){
  436. $result['business_no_limit'] = $config['business_no_limit'];
  437. }
  438. //是否显示 个人实名认证
  439. $result['person_show'] = $config['status'] ?? 0;
  440. $result['business_show'] = $config['business_status'] ?? 0;
  441. $auth = RealAuthUser::find()->select('id,auth,auth_type,real_name,id_no')->where(['mall_id'=>$mall_id,'user_id'=>$user_id])->asArray()->one();
  442. if($auth){
  443. $result['is_apply'] = 1;
  444. $result['auth'] = $auth['auth'];
  445. $result['auth_type'] = $auth['auth_type'];
  446. $real_auth_detail = RealAuthDetail::findOne(['auth_id'=>$auth['id'],'auth_type'=>$auth['auth_type'],'status'=>StatusEnum::ENABLED]);
  447. unset($auth['auth'],$auth['auth_type']);
  448. if($real_auth_detail){
  449. $detail['detail'] = $real_auth_detail['detail'];
  450. if(!is_array($detail['detail'])){
  451. $detail['detail'] = json_decode($detail['detail'],true);
  452. }
  453. $result['check_status'] = $real_auth_detail['check_status'];
  454. $result['remark'] = $real_auth_detail['remark'];
  455. $result['info'] = array_merge($auth,$detail);
  456. }
  457. if($result['business_no_limit'] == 1){
  458. $real_auth_detail_business = RealAuthDetail::find()->where(['auth_id'=>$auth['id'],'auth_type'=>RealAuthUser::BUSINESS,'status'=>StatusEnum::ENABLED])->select('detail,check_status,remark')->asArray()->one();
  459. if($real_auth_detail_business){
  460. $result['check_status'] = $real_auth_detail_business['check_status'];
  461. $result['remark'] = $real_auth_detail_business['remark'];
  462. if(!is_array($real_auth_detail_business['detail'])){
  463. $real_auth_detail_business['detail'] = json_decode($real_auth_detail_business['detail'],true);
  464. }
  465. $result['business_info'] = array_merge($auth,$real_auth_detail_business);
  466. if($auth['auth_type'] == RealAuthUser::USER){
  467. $result['upgrade_status'] = 1;
  468. }
  469. }
  470. }
  471. }
  472. return $result;
  473. }
  474. }