Login.php 13 KB

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