validate([ 'email' => ['required', 'email'], 'password' => ['string'], ]); $key = 'operator-login:'.mb_strtolower($this->email).'|'.request()->ip(); if (RateLimiter::tooManyAttempts($key, 5)) { throw ValidationException::withMessages([ 'email' => __('auth.throttle', ['seconds' => RateLimiter::availableIn($key)]), ]); } $operator = Operator::where('email', $this->email)->first(); // One message for every failure — a different message for "no such // account" tells a stranger which addresses are operators. if ($operator === null || ! Hash::check($this->password, $operator->password) || ! $operator->isActive() || ! $operator->isOperator()) { RateLimiter::hit($key, 60); $this->reset('password'); throw ValidationException::withMessages(['email' => __('auth.failed')]); } RateLimiter::clear($key); if ($operator->two_factor_confirmed_at !== null) { // Not signed in yet. The id is parked in the session and the guard // stays untouched until the code checks out. session(['operator.2fa.id' => $operator->id, 'operator.2fa.remember' => $this->remember]); $this->redirectRoute('admin.two-factor', navigate: false); return; } $this->completeLoginAndRedirect($operator, $this->remember); } /** Shared with the two-factor challenge, so both exits behave identically. */ public static function completeLogin(Operator $operator, bool $remember): void { Auth::guard('operator')->login($operator, $remember); session()->regenerate(); $operator->forceFill(['last_login_at' => now()])->save(); } private function completeLoginAndRedirect(Operator $operator, bool $remember): void { self::completeLogin($operator, $remember); $this->redirect(AdminArea::home(), navigate: false); } public function render() { return view('livewire.auth.operator-login'); } }