check()) { return redirect()->route('user.home'); } return view('user.login'); } public function home() { return view('user.shell'); } public function login(Request $request, AdminGoogle2fa $google2fa): JsonResponse { try { $credentials = $request->validate([ 'username' => 'required|string|min:2|max:64', 'password' => 'required|string|max:128', 'GACode' => 'nullable|string|max:16', ], [ 'username.required' => '请输入用户名', 'password.required' => '请输入密码', ]); } catch (ValidationException $e) { return response()->json([ 'code' => 1, 'msg' => collect($e->errors())->flatten()->implode('
'), ]); } $throttleKey = $this->throttleKey($request); if (RateLimiter::tooManyAttempts($throttleKey, self::MAX_ATTEMPTS)) { $seconds = RateLimiter::availableIn($throttleKey); return response()->json([ 'code' => 1, 'msg' => '登陆失败次数过多,请'.$seconds.'秒后再重试', ]); } /** @var User|null $user */ $user = User::query()->where('username', $credentials['username'])->first(); if ($user && $user->isLocked()) { return response()->json([ 'code' => 1, 'msg' => '账号已被封锁(连续输错密码 '.self::MAX_ATTEMPTS.' 次),请联系管理员解除', ]); } if ($user && ! $user->isEnabled()) { RateLimiter::hit($throttleKey, self::DECAY_SECONDS); return response()->json(['code' => 1, 'msg' => '账号已禁用']); } if (! Auth::guard('agent')->attempt( ['username' => $credentials['username'], 'password' => $credentials['password']], $request->boolean('remember') )) { RateLimiter::hit($throttleKey, self::DECAY_SECONDS); if ($user) { $justLocked = $user->recordFailedLogin(self::MAX_ATTEMPTS); if ($justLocked) { SystemLog::record( $user, 'agent', SystemLog::ACTION_AGENT_LOCKED, '代理「'.$user->username.'」连续输错密码 '.self::MAX_ATTEMPTS.' 次,账号被自动封锁', $request, ); return response()->json([ 'code' => 1, 'msg' => '密码连续输错 '.self::MAX_ATTEMPTS.' 次,账号已被封锁,请联系管理员解除', ]); } $remaining = self::MAX_ATTEMPTS - (int) $user->fresh()->login_attempts; if ($remaining > 0) { return response()->json([ 'code' => 1, 'msg' => '用户名或密码错误(剩余 '.$remaining.' 次尝试机会)', ]); } } return response()->json(['code' => 1, 'msg' => '用户名或密码错误']); } /** @var User $user */ $user = Auth::guard('agent')->user(); if ($user->requiresLoginGoogle()) { $code = (string) ($credentials['GACode'] ?? ''); if ($code === '') { Auth::guard('agent')->logout(); return response()->json(['code' => 1, 'msg' => '请输入谷歌验证码!']); } if (! $google2fa->verify((string) $user->google_secret, $code)) { Auth::guard('agent')->logout(); RateLimiter::hit($throttleKey, self::DECAY_SECONDS); return response()->json(['code' => 1, 'msg' => '谷歌验证码不正确!']); } } RateLimiter::clear($throttleKey); $user->clearLoginAttempts(); $request->session()->regenerate(); return response()->json([ 'code' => 0, 'msg' => '登录成功', 'data' => route('user.home'), ]); } public function logout(Request $request) { Auth::guard('agent')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect()->route('user.login'); } private function throttleKey(Request $request): string { return Str::transliterate(Str::lower((string) $request->input('username')).'|'.VisitorIp::fromRequest($request)); } }