AccountController.php 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. <?php
  2. namespace plugin\admin\app\controller;
  3. use plugin\admin\app\common\Auth;
  4. use plugin\admin\app\common\Util;
  5. use plugin\admin\app\model\Admin;
  6. use support\exception\BusinessException;
  7. use support\Request;
  8. use support\Response;
  9. use Throwable;
  10. use Webman\Captcha\CaptchaBuilder;
  11. use Webman\Captcha\PhraseBuilder;
  12. /**
  13. * 管理员账户
  14. */
  15. class AccountController extends Crud
  16. {
  17. /**
  18. * 不需要登录的方法
  19. * @var string[]
  20. */
  21. protected $noNeedLogin = ['login', 'logout', 'captcha'];
  22. /**
  23. * 不需要鉴权的方法
  24. * @var string[]
  25. */
  26. protected $noNeedAuth = ['info'];
  27. /**
  28. * @var Admin
  29. */
  30. protected $model = null;
  31. /**
  32. * 构造函数
  33. */
  34. public function __construct()
  35. {
  36. $this->model = new Admin;
  37. }
  38. /**
  39. * 账户设置
  40. * @return Response
  41. * @throws Throwable
  42. */
  43. public function index()
  44. {
  45. return raw_view('account/index');
  46. }
  47. /**
  48. * 登录
  49. * @param Request $request
  50. * @return Response
  51. * @throws BusinessException
  52. */
  53. public function login(Request $request): Response
  54. {
  55. $this->checkDatabaseAvailable();
  56. $captcha = $request->post('captcha', '');
  57. if (strtolower($captcha) !== session('captcha-login')) {
  58. return $this->json(1, '验证码错误');
  59. }
  60. $request->session()->forget('captcha-login');
  61. $username = $request->post('username', '');
  62. $password = $request->post('password', '');
  63. if (!$username) {
  64. return $this->json(1, '用户名不能为空');
  65. }
  66. $this->checkLoginLimit($username);
  67. $admin = Admin::where('username', $username)->first();
  68. if (!$admin || !Util::passwordVerify($password, $admin->password)) {
  69. return $this->json(1, '账户不存在或密码错误');
  70. }
  71. if ($admin->status != 0) {
  72. return $this->json(1, '当前账户暂时无法登录');
  73. }
  74. $admin->login_at = date('Y-m-d H:i:s');
  75. $admin->save();
  76. $this->removeLoginLimit($username);
  77. $admin = $admin->toArray();
  78. $session = $request->session();
  79. $admin['password'] = md5($admin['password']);
  80. $session->set('admin', $admin);
  81. return $this->json(0, '登录成功', [
  82. 'nickname' => $admin['nickname'],
  83. 'token' => $request->sessionId(),
  84. ]);
  85. }
  86. protected function checkDatabaseAvailable()
  87. {
  88. if (!config('plugin.admin.database')) {
  89. throw new BusinessException('请重启webman');
  90. }
  91. }
  92. /**
  93. * 检查登录频率限制
  94. * @param $username
  95. * @return void
  96. * @throws BusinessException
  97. */
  98. protected function checkLoginLimit($username)
  99. {
  100. $limit_log_path = runtime_path() . '/login';
  101. if (!is_dir($limit_log_path)) {
  102. mkdir($limit_log_path, 0777, true);
  103. }
  104. $limit_file = $limit_log_path . '/' . md5($username) . '.limit';
  105. $time = date('YmdH') . ceil(date('i') / 5);
  106. $limit_info = [];
  107. if (is_file($limit_file)) {
  108. $json_str = file_get_contents($limit_file);
  109. $limit_info = json_decode($json_str, true);
  110. }
  111. if (!$limit_info || $limit_info['time'] != $time) {
  112. $limit_info = [
  113. 'username' => $username,
  114. 'count' => 0,
  115. 'time' => $time
  116. ];
  117. }
  118. $limit_info['count'] ++;
  119. file_put_contents($limit_file, json_encode($limit_info));
  120. if ($limit_info['count'] >= 5) {
  121. throw new BusinessException('登录失败次数过多,请5分钟后再试');
  122. }
  123. }
  124. /**
  125. * 解除登录频率限制
  126. * @param $username
  127. * @return void
  128. */
  129. protected function removeLoginLimit($username)
  130. {
  131. $limit_log_path = runtime_path() . '/login';
  132. $limit_file = $limit_log_path . '/' . md5($username) . '.limit';
  133. if (is_file($limit_file)) {
  134. unlink($limit_file);
  135. }
  136. }
  137. /**
  138. * 退出
  139. * @param Request $request
  140. * @return Response
  141. */
  142. public function logout(Request $request): Response
  143. {
  144. $request->session()->delete('admin');
  145. return $this->json(0);
  146. }
  147. /**
  148. * 获取登录信息
  149. * @param Request $request
  150. * @return Response
  151. */
  152. public function info(Request $request): Response
  153. {
  154. $admin = admin();
  155. if (!$admin) {
  156. return $this->json(1);
  157. }
  158. $info = [
  159. 'id' => $admin['id'],
  160. 'username' => $admin['username'],
  161. 'nickname' => $admin['nickname'],
  162. 'avatar' => $admin['avatar'],
  163. 'email' => $admin['email'],
  164. 'mobile' => $admin['mobile'],
  165. 'isSuperAdmin' => Auth::isSuperAdmin(),
  166. 'token' => $request->sessionId(),
  167. ];
  168. return $this->json(0, 'ok', $info);
  169. }
  170. /**
  171. * 修改密码
  172. * @param Request $request
  173. * @return Response
  174. */
  175. public function password(Request $request): Response
  176. {
  177. $hash = Admin::find(admin_id())['password'];
  178. $password = $request->post('password');
  179. if (!$password) {
  180. return $this->json(2, '密码不能为空');
  181. }
  182. if ($request->post('password_confirm') !== $password) {
  183. return $this->json(3, '两次密码输入不一致');
  184. }
  185. if (!Util::passwordVerify($request->post('old_password'), $hash)) {
  186. return $this->json(1, '原始密码不正确');
  187. }
  188. $update_data = [
  189. 'password' => Util::passwordHash($password)
  190. ];
  191. Admin::where('id', admin_id())->update($update_data);
  192. return $this->json(0);
  193. }
  194. /**
  195. * 更新
  196. * @param Request $request
  197. * @return Response
  198. */
  199. public function update(Request $request): Response
  200. {
  201. $allow_column = [
  202. 'nickname' => 'nickname',
  203. 'avatar' => 'avatar',
  204. 'email' => 'email',
  205. 'mobile' => 'mobile',
  206. ];
  207. $data = $request->post();
  208. $update_data = [];
  209. foreach ($allow_column as $key => $column) {
  210. if (isset($data[$key])) {
  211. $update_data[$column] = $data[$key];
  212. }
  213. }
  214. if (isset($update_data['password'])) {
  215. $update_data['password'] = Util::passwordHash($update_data['password']);
  216. }
  217. Admin::where('id', admin_id())->update($update_data);
  218. $admin = admin();
  219. unset($update_data['password']);
  220. foreach ($update_data as $key => $value) {
  221. $admin[$key] = $value;
  222. }
  223. $request->session()->set('admin', $admin);
  224. return $this->json(0);
  225. }
  226. /**
  227. * 验证码
  228. * @param Request $request
  229. * @param string $type
  230. * @return Response
  231. */
  232. public function captcha(Request $request, string $type = 'login'): Response
  233. {
  234. $builder = new PhraseBuilder(4, 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKMNPQRSTUVWXYZ');
  235. $captcha = new CaptchaBuilder(null, $builder);
  236. $captcha->build(120);
  237. $request->session()->set("captcha-$type", strtolower($captcha->getPhrase()));
  238. $img_content = $captcha->get();
  239. return response($img_content, 200, ['Content-Type' => 'image/jpeg']);
  240. }
  241. }