Login.php 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  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. $ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, []);
  140. }
  141. if ($ret) {
  142. Sms::flush($mobile, 'mobilelogin');
  143. $user = $this->auth->getUserinfo();
  144. $user['avatar'] = cdnurl($user['avatar'], true);
  145. $data = ['token' => $this->auth->getToken(), 'user' => $user];
  146. $this->success(__('Logged in successful'), $data);
  147. } else {
  148. $this->error($this->auth->getError());
  149. }
  150. }
  151. /**
  152. * 注册会员
  153. *
  154. * @param string $username 用户名
  155. * @param string $password 密码
  156. * @param string $email 邮箱
  157. * @param string $mobile 手机号
  158. * @param string $code 验证码
  159. */
  160. public function register()
  161. {
  162. $params = $this->request->param();
  163. $username = $params['username'] ?? '';
  164. $password = $params['password'] ?? '';
  165. $mobile = $params['mobile'] ?? '';
  166. $code = $params['captcha'] ?? '';
  167. // 验证器
  168. $validate = new \app\api\validate\User();
  169. if (!$validate->check($params, [], 'register')) {
  170. $this->error($validate->getError());
  171. }
  172. $invite_id = $this->request->post('invite_id');
  173. if ($invite_id) {
  174. \think\Cookie::set('inviter', $invite_id);
  175. }
  176. $ret = Sms::check($mobile, $code, 'register');
  177. if (!$ret) {
  178. $this->error(__('Captcha is incorrect'));
  179. }
  180. $ret = $this->auth->register($username, $password, '', $mobile, []);
  181. if ($ret) {
  182. $user = $this->auth->getUserinfo();
  183. $user['avatar'] = cdnurl($user['avatar'], true);
  184. $this->success(__('Sign up successful'), [
  185. 'token' => $this->auth->getToken(),
  186. 'user' => $user
  187. ]);
  188. } else {
  189. $this->error($this->auth->getError());
  190. }
  191. }
  192. /**
  193. * 第三方登录[绑定] 小程序
  194. */
  195. public function wxLogin()
  196. {
  197. $code = $this->request->post("code");
  198. $rawData = $this->request->post("rawData/a", '', 'trim');
  199. if (!$code) {
  200. $this->error("参数不正确");
  201. }
  202. $rawData = $rawData ?: ['nickName' => '微信用户'];
  203. $third = get_addon_info('third');
  204. if (!$third || !$third['state']) {
  205. $this->error("请在后台插件管理安装第三方登录插件并启用");
  206. }
  207. if (!config('shop.wx_appid') || !config('shop.wx_app_secret')) {
  208. $this->error("请在后台配置微信小程序参数");
  209. }
  210. $json = (new WechatService(Wechat::miniProgram()))->getWechatSession($code);
  211. if (isset($json['openid'])) {
  212. $userinfo = [
  213. 'platform' => 'wechat',
  214. 'apptype' => 'miniapp',
  215. 'openid' => $json['openid'],
  216. 'userinfo' => [
  217. 'nickname' => $rawData['nickName'] ?? '',
  218. 'avatar' => $rawData['avatarUrl'] ?? ''
  219. ],
  220. 'openname' => $rawData['nickName'] ?? '',
  221. 'access_token' => $json['session_key'],
  222. 'refresh_token' => '',
  223. 'expires_in' => $json['expires_in'] ?? 0,
  224. 'unionid' => $json['unionid'] ?? ''
  225. ];
  226. $third = [
  227. 'nickname' => $rawData['nickName'] ?? '',
  228. 'avatar' => $rawData['avatarUrl'] ?? ''
  229. ];
  230. $user = null;
  231. if ($this->auth->isLogin() || Service::isBindThird($userinfo['platform'], $userinfo['openid'])) {
  232. Service::connect($userinfo['platform'], $userinfo);
  233. } else {
  234. // 是否自动创建账号
  235. if (config('shop.wechatautocreate')) {
  236. Service::connect($userinfo['platform'], $userinfo);
  237. } else {
  238. Session::set('third-userinfo', $userinfo);
  239. $this->success('授权成功!', ['third' => $third, 'openid' => $json['openid'], 'bind' => true]);
  240. }
  241. }
  242. $user = $this->auth->getUserinfo();
  243. $this->success('授权成功!', ['user' => $user, 'third' => $third, 'openid' => $json['openid']]);
  244. }
  245. $this->error("授权失败," . ($json['errmsg'] ?? "未知错误"));
  246. }
  247. /**
  248. * 微信手机号授权登录
  249. */
  250. public function wechatMobileLogin()
  251. {
  252. $code = $this->request->post("code");
  253. $logincode = $this->request->post("logincode");
  254. $bind = $this->request->post("bind");
  255. $data = (new WechatService(Wechat::miniProgram()))->getWechatMobile($code);
  256. if ($data) {
  257. $mobile = $data['phoneNumber'];
  258. //获取openid和unionid
  259. $json = (new WechatService(Wechat::miniProgram()))->getWechatSession($logincode);
  260. $openid = $json['openid'] ?? '';
  261. $unionid = $json['unionid'] ?? '';
  262. $user = \app\common\model\User::getByMobile($mobile);
  263. if ($user) {
  264. if ($user->status != StatusEnum::ENABLED) {
  265. $this->error(__('Account is locked'));
  266. }
  267. //如果已经有账号则直接登录
  268. $ret = $this->auth->direct($user->id);
  269. } else {
  270. $ret = $this->auth->register($mobile, Random::alnum(), '', $mobile, ['nickname' => substr_replace($mobile, '****', 3, 4)]);
  271. }
  272. //判断是否绑定模式,openid是否有关联,没有关联的情况下手动进行关联
  273. if ($bind && $openid) {
  274. if (Service::isBindThird('wechat', $openid)) {
  275. $this->error("手机号已经绑定其它账号");
  276. }
  277. // 在第三方登录表中创建关联
  278. $values = ['user_id' => $this->auth->id, 'platform' => 'wechat', 'openid' => $openid, 'unionid' => $unionid, 'openname' => '微信用户', 'apptype' => 'miniapp'];
  279. Third::create($values, true);
  280. }
  281. if ($ret) {
  282. $data = ['user' => $this->auth->getUserinfo(), 'token' => $this->auth->getToken(), 'openid' => $openid];
  283. $this->success('授权成功!', $data);
  284. } else {
  285. $this->error($this->auth->getError());
  286. }
  287. } else {
  288. $this->error("授权失败,请重试");
  289. }
  290. }
  291. /**
  292. * APP登录 todo 需要修改
  293. */
  294. public function appLogin()
  295. {
  296. $code = $this->request->post("code");
  297. $scope = $this->request->post("scope");
  298. if (!$code) {
  299. $this->error("参数不正确");
  300. }
  301. $third = get_addon_info('third');
  302. if (!$third || !$third['state']) {
  303. $this->error("请在后台插件管理安装第三方登录插件并启用");
  304. }
  305. Session::set('state', $code);
  306. $config = [
  307. 'app_id' => Config::get('shop.app_id'),
  308. 'app_secret' => Config::get('shop.app_secret'),
  309. 'scope' => $scope
  310. ];
  311. if (!$config['app_id'] || !$config['app_secret']) {
  312. $this->error("请在后台配置移动端APP参数");
  313. }
  314. $wechat = new \addons\third\library\Wechat($config);
  315. $userinfo = $wechat->getUserInfo(['code' => $code, 'state' => $code]);
  316. if (!$userinfo) {
  317. $this->error(__('操作失败'));
  318. }
  319. //判断是否需要绑定
  320. $userinfo['apptype'] = 'native';
  321. $userinfo['platform'] = 'wechat';
  322. $third = [
  323. 'avatar' => $userinfo['userinfo']['avatar'],
  324. 'nickname' => $userinfo['userinfo']['nickname']
  325. ];
  326. $user = null;
  327. if ($this->auth->isLogin() || Service::isBindThird($userinfo['platform'], $userinfo['openid'], $userinfo['apptype'], $userinfo['unionid'])) {
  328. Service::connect($userinfo['platform'], $userinfo);
  329. $user = $this->auth->getUserinfo();
  330. } else {
  331. Session::set('third-userinfo', $userinfo);
  332. }
  333. $this->success('授权成功!', ['user' => $user, 'third' => $third]);
  334. }
  335. /**
  336. * 获取Openid(仅用于微信小程序)
  337. */
  338. public function getWechatOpenid()
  339. {
  340. $code = $this->request->post("login_code");
  341. $json = (new WechatService(Wechat::miniProgram()))->getWechatSession($code);
  342. $this->success('获取成功!', ['openid' => $json['openid'] ?? '']);
  343. }
  344. }