Login.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370
  1. <?php
  2. namespace app\api\controller;
  3. use addons\third\model\Third;
  4. use app\common\library\Auth;
  5. use app\common\library\Sms;
  6. use app\common\library\Ems;
  7. use fast\Random;
  8. use think\Validate;
  9. use fast\Http;
  10. use addons\third\library\Service;
  11. use app\common\Enum\StatusEnum;
  12. use think\Config;
  13. use think\Env;
  14. use think\Session;
  15. class Login extends Base
  16. {
  17. protected $noNeedLogin = ['*'];
  18. public function _initialize()
  19. {
  20. parent::_initialize();
  21. if (!$this->request->isPost()) {
  22. $this->error('请求错误');
  23. }
  24. Auth::instance()->setAllowFields(array_merge(['username'], $this->allowFields));
  25. }
  26. /**
  27. * 会员登录
  28. *
  29. * @param string $account 账号
  30. * @param string $password 密码
  31. */
  32. public function login()
  33. {
  34. $params = $this->request->param();
  35. $account = $params['account'] ?? '';
  36. $password = $params['password'] ?? '';
  37. //增加验证器
  38. $validate = new \app\api\validate\User();
  39. if (!$validate->check($params, [], 'login')) {
  40. $this->error($validate->getError());
  41. }
  42. $ret = $this->auth->login($account, $password);
  43. if ($ret) {
  44. $user = $this->auth->getUserinfo();
  45. $user['avatar'] = cdnurl($user['avatar'], true);
  46. $this->success(__('Logged in successful'), [
  47. 'token' => $this->auth->getToken(),
  48. 'user' => $user
  49. ]);
  50. } else {
  51. $this->error($this->auth->getError());
  52. }
  53. }
  54. /**
  55. * 重置密码
  56. *
  57. * @param string $mobile 手机号
  58. * @param string $newpassword 新密码
  59. * @param string $captcha 验证码
  60. */
  61. public function resetpwd()
  62. {
  63. $params = $this->request->param();
  64. $type = $params['type'] ?? '';
  65. $mobile = $params['mobile'] ?? '';
  66. $email = $params['email'] ?? '';
  67. $newpassword = $params['newpassword'] ?? '';
  68. $captcha = $params['captcha'] ?? '';
  69. //验证器
  70. $validate = new \app\api\validate\UserCancel();
  71. if (!$validate->check($params, [], 'resetpwd')) {
  72. $this->error($validate->getError());
  73. }
  74. if ($type == 'mobile') {
  75. $user = \app\common\model\User::getByMobile($mobile);
  76. if (!$user) {
  77. $this->error(__('User not found'));
  78. }
  79. if (!Env::get('app.app_debug') && $captcha != Env::get('app.DEFAULT_SMSCODE')) {
  80. $ret = Sms::check($mobile, $captcha, 'resetpwd');
  81. if (!$ret) {
  82. $this->error(__('Captcha is incorrect'));
  83. }
  84. }
  85. Sms::flush($mobile, 'resetpwd');
  86. } else {
  87. $user = \app\common\model\User::getByEmail($email);
  88. if (!$user) {
  89. $this->error(__('User not found'));
  90. }
  91. $ret = Ems::check($email, $captcha, 'resetpwd');
  92. if (!$ret) {
  93. $this->error(__('Captcha is incorrect'));
  94. }
  95. Ems::flush($email, 'resetpwd');
  96. }
  97. //模拟一次登录
  98. $this->auth->direct($user->id);
  99. $ret = $this->auth->changepwd($newpassword, '', true);
  100. if ($ret) {
  101. $this->success(__('Reset password successful'));
  102. } else {
  103. $this->error($this->auth->getError());
  104. }
  105. }
  106. /**
  107. * 手机验证码登录
  108. *
  109. * @param string $mobile 手机号
  110. * @param string $captcha 验证码
  111. */
  112. public function mobilelogin()
  113. {
  114. $params = $this->request->param();
  115. $mobile = $params['mobile'] ?? '';
  116. $captcha = $params['captcha'] ?? '';
  117. $invite_id = $params['invite_id'] ?? '';
  118. // 验证器
  119. $validate = new \app\api\validate\User();
  120. if (!$validate->check($params, [], 'mobilelogin')) {
  121. $this->error($validate->getError());
  122. }
  123. // 这里需要处理 测试环境 env('app_debug') 为 true 时,不进行验证码验证 校验 验证码固定为env的配置 DEFAULT_SMSCODE: 123456
  124. if (!Env::get('app.app_debug') && $captcha != Env::get('app.DEFAULT_SMSCODE')) {
  125. if (!Sms::check($mobile, $captcha, 'mobilelogin')) {
  126. $this->error(__('Captcha is incorrect'));
  127. }
  128. }
  129. $user = \app\common\model\User::getByMobile($mobile);
  130. if ($user) {
  131. if ($user->status != StatusEnum::ENABLED) {
  132. $this->error(__('Account is locked'));
  133. }
  134. //如果已经有账号则直接登录
  135. $ret = $this->auth->direct($user->id);
  136. } else {
  137. $ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, []);
  138. }
  139. if ($ret) {
  140. Sms::flush($mobile, 'mobilelogin');
  141. $user = $this->auth->getUserinfo();
  142. $user['avatar'] = cdnurl($user['avatar'], true);
  143. $data = ['token' => $this->auth->getToken(), 'user' => $user];
  144. $this->success(__('Logged in successful'), $data);
  145. } else {
  146. $this->error($this->auth->getError());
  147. }
  148. }
  149. /**
  150. * 注册会员
  151. *
  152. * @param string $username 用户名
  153. * @param string $password 密码
  154. * @param string $email 邮箱
  155. * @param string $mobile 手机号
  156. * @param string $code 验证码
  157. */
  158. public function register()
  159. {
  160. $params = $this->request->param();
  161. $username = $params['username'] ?? '';
  162. $password = $params['password'] ?? '';
  163. $mobile = $params['mobile'] ?? '';
  164. $code = $params['captcha'] ?? '';
  165. // 验证器
  166. $validate = new \app\api\validate\User();
  167. if (!$validate->check($params, [], 'register')) {
  168. $this->error($validate->getError());
  169. }
  170. $invite_id = $this->request->post('invite_id');
  171. if ($invite_id) {
  172. \think\Cookie::set('inviter', $invite_id);
  173. }
  174. $ret = Sms::check($mobile, $code, 'register');
  175. if (!$ret) {
  176. $this->error(__('Captcha is incorrect'));
  177. }
  178. $ret = $this->auth->register($username, $password, '', $mobile, []);
  179. if ($ret) {
  180. $user = $this->auth->getUserinfo();
  181. $user['avatar'] = cdnurl($user['avatar'], true);
  182. $this->success(__('Sign up successful'), [
  183. 'token' => $this->auth->getToken(),
  184. 'user' => $user
  185. ]);
  186. } else {
  187. $this->error($this->auth->getError());
  188. }
  189. }
  190. /**
  191. * 第三方登录[绑定] 小程序
  192. */
  193. public function wxLogin()
  194. {
  195. $code = $this->request->post("code");
  196. $rawData = $this->request->post("rawData/a", '', 'trim');
  197. if (!$code) {
  198. $this->error("参数不正确");
  199. }
  200. $rawData = $rawData ?: ['nickName' => '微信用户'];
  201. $third = get_addon_info('third');
  202. if (!$third || !$third['state']) {
  203. $this->error("请在后台插件管理安装第三方登录插件并启用");
  204. }
  205. if (!config('shop.wx_appid') || !config('shop.wx_app_secret')) {
  206. $this->error("请在后台配置微信小程序参数");
  207. }
  208. $json = (new \addons\shop\library\Wechat\Service())->getWechatSession($code);
  209. if (isset($json['openid'])) {
  210. $userinfo = [
  211. 'platform' => 'wechat',
  212. 'apptype' => 'miniapp',
  213. 'openid' => $json['openid'],
  214. 'userinfo' => [
  215. 'nickname' => $rawData['nickName'] ?? '',
  216. 'avatar' => $rawData['avatarUrl'] ?? ''
  217. ],
  218. 'openname' => $rawData['nickName'] ?? '',
  219. 'access_token' => $json['session_key'],
  220. 'refresh_token' => '',
  221. 'expires_in' => $json['expires_in'] ?? 0,
  222. 'unionid' => $json['unionid'] ?? ''
  223. ];
  224. $third = [
  225. 'nickname' => $rawData['nickName'] ?? '',
  226. 'avatar' => $rawData['avatarUrl'] ?? ''
  227. ];
  228. $user = null;
  229. if ($this->auth->isLogin() || Service::isBindThird($userinfo['platform'], $userinfo['openid'])) {
  230. Service::connect($userinfo['platform'], $userinfo);
  231. } else {
  232. // 是否自动创建账号
  233. if (config('shop.wechatautocreate')) {
  234. Service::connect($userinfo['platform'], $userinfo);
  235. } else {
  236. Session::set('third-userinfo', $userinfo);
  237. $this->success('授权成功!', ['third' => $third, 'openid' => $json['openid'], 'bind' => true]);
  238. }
  239. }
  240. $user = $this->auth->getUserinfo();
  241. $this->success('授权成功!', ['user' => $user, 'third' => $third, 'openid' => $json['openid']]);
  242. }
  243. $this->error("授权失败," . ($json['errmsg'] ?? "未知错误"));
  244. }
  245. /**
  246. * 微信手机号授权登录
  247. */
  248. public function wechatMobileLogin()
  249. {
  250. $code = $this->request->post("code");
  251. $logincode = $this->request->post("logincode");
  252. $bind = $this->request->post("bind");
  253. $data = (new \app\common\library\Wechat\Service())->getWechatMobile($code);
  254. if ($data) {
  255. $mobile = $data['phoneNumber'];
  256. //获取openid和unionid
  257. $json = (new \app\common\library\Wechat\Service())->getWechatSession($logincode);
  258. $openid = $json['openid'] ?? '';
  259. $unionid = $json['unionid'] ?? '';
  260. $user = \app\common\model\User::getByMobile($mobile);
  261. if ($user) {
  262. if ($user->status != StatusEnum::ENABLED) {
  263. $this->error(__('Account is locked'));
  264. }
  265. //如果已经有账号则直接登录
  266. $ret = $this->auth->direct($user->id);
  267. } else {
  268. $ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, ['nickname' => substr_replace($mobile, '****', 3, 4)]);
  269. }
  270. //判断是否绑定模式,openid是否有关联,没有关联的情况下手动进行关联
  271. if ($bind && $openid) {
  272. if (Service::isBindThird('wechat', $openid)) {
  273. $this->error("手机号已经绑定其它账号");
  274. }
  275. // 在第三方登录表中创建关联
  276. $values = ['user_id' => $this->auth->id, 'platform' => 'wechat', 'openid' => $openid, 'unionid' => $unionid, 'openname' => '微信用户', 'apptype' => 'miniapp'];
  277. Third::create($values, true);
  278. }
  279. if ($ret) {
  280. $data = ['user' => $this->auth->getUserinfo(), 'token' => $this->auth->getToken(), 'openid' => $openid];
  281. $this->success('授权成功!', $data);
  282. } else {
  283. $this->error($this->auth->getError());
  284. }
  285. } else {
  286. $this->error("授权失败,请重试");
  287. }
  288. }
  289. /**
  290. * APP登录
  291. */
  292. public function appLogin()
  293. {
  294. $code = $this->request->post("code");
  295. $scope = $this->request->post("scope");
  296. if (!$code) {
  297. $this->error("参数不正确");
  298. }
  299. $third = get_addon_info('third');
  300. if (!$third || !$third['state']) {
  301. $this->error("请在后台插件管理安装第三方登录插件并启用");
  302. }
  303. Session::set('state', $code);
  304. $config = [
  305. 'app_id' => Config::get('shop.app_id'),
  306. 'app_secret' => Config::get('shop.app_secret'),
  307. 'scope' => $scope
  308. ];
  309. if (!$config['app_id'] || !$config['app_secret']) {
  310. $this->error("请在后台配置移动端APP参数");
  311. }
  312. $wechat = new \addons\third\library\Wechat($config);
  313. $userinfo = $wechat->getUserInfo(['code' => $code, 'state' => $code]);
  314. if (!$userinfo) {
  315. $this->error(__('操作失败'));
  316. }
  317. //判断是否需要绑定
  318. $userinfo['apptype'] = 'native';
  319. $userinfo['platform'] = 'wechat';
  320. $third = [
  321. 'avatar' => $userinfo['userinfo']['avatar'],
  322. 'nickname' => $userinfo['userinfo']['nickname']
  323. ];
  324. $user = null;
  325. if ($this->auth->isLogin() || Service::isBindThird($userinfo['platform'], $userinfo['openid'], $userinfo['apptype'], $userinfo['unionid'])) {
  326. Service::connect($userinfo['platform'], $userinfo);
  327. $user = $this->auth->getUserinfo();
  328. } else {
  329. Session::set('third-userinfo', $userinfo);
  330. }
  331. $this->success('授权成功!', ['user' => $user, 'third' => $third]);
  332. }
  333. /**
  334. * 获取Openid(仅用于微信小程序)
  335. */
  336. public function getWechatOpenid()
  337. {
  338. $code = $this->request->post("logincode");
  339. $json = (new \addons\shop\library\Wechat\Service())->getWechatSession($code);
  340. $this->success('获取成功!', ['openid' => $json['openid'] ?? '']);
  341. }
  342. }