=60 znaków) i włączony jest flag SOFTSPM_REHASH - przepisujemy hash * na bcrypt. Domyślnie WYŁĄCZONE, żeby nie uszkodzić zbyt krótkiej kolumny. * Decyzja o rozszerzeniu kolumny / osobnej kolumnie do ustalenia. */ class LoginController extends Controller { /** Pokaż formularz logowania. */ public function show() { return view('auth.login'); } /** Obsłuż próbę logowania. */ public function attempt(Request $request) { // Faza testów: oddział może być wymuszony w configu (pole ukryte w logowaniu). $forcedDepartment = config('softspm.login_department'); $rules = [ 'username' => ['required', 'string', 'max:100'], 'password' => ['required', 'string'], 'lang' => ['nullable', 'in:pl,en,de'], ]; if (! $forcedDepartment) { $rules['department'] = ['required', 'string', Rule::in(config('softspm.departments'))]; } $credentials = $request->validate($rules); $department = $forcedDepartment ?: $credentials['department']; $user = User::query() ->where('USR_USERNAME', $credentials['username']) ->where('USR_STATUS', '1') ->first(); if (! $user || ! $this->passwordMatches($credentials['password'], $user->USR_PASSWORD)) { throw ValidationException::withMessages([ 'username' => 'Nieprawidłowy login lub hasło.', ]); } // Opcjonalna migracja MD5 -> bcrypt (patrz docblock klasy). $this->maybeRehash($user, $credentials['password']); Auth::login($user); $request->session()->regenerate(); // Oddział filtrujący listy obiektów (odpowiednik legacy 'syndis_eq_stock'). $request->session()->put('department', $department); // Zapamiętaj wybrany język UI (i18n w kolejnym etapie). if (! empty($credentials['lang'])) { $request->session()->put('locale', $credentials['lang']); } return redirect()->intended(route('dashboard')); } /** Wyloguj. */ public function logout(Request $request) { Auth::logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect()->route('login'); } /** * Weryfikacja hasła: bcrypt (nowe) lub md5 (legacy). */ private function passwordMatches(string $plain, ?string $stored): bool { if (empty($stored)) { return false; } // Hash bcrypt zaczyna się od $2y$ / $2a$ - sprawdź najpierw. if (str_starts_with($stored, '$2')) { return Hash::check($plain, $stored); } // Legacy: md5 (32 znaki hex). hash_equals chroni przed timing-attack. return hash_equals(strtolower($stored), md5($plain)); } /** * Po logowaniu MD5 przepisz hash na bcrypt - tylko gdy bezpiecznie. */ private function maybeRehash(User $user, string $plain): void { if (! config('softspm.rehash_passwords', false)) { return; } if (str_starts_with((string) $user->USR_PASSWORD, '$2')) { return; // już bcrypt } $user->USR_PASSWORD = Hash::make($plain); $user->save(); } }