mivita/app/Http/Controllers/Portal/Auth/LoginController.php
2025-10-20 17:42:08 +02:00

206 lines
8.3 KiB
PHP

<?php
namespace App\Http\Controllers\Portal\Auth;
use Carbon\Carbon;
use App\Services\Util;
use Illuminate\Support\Str;
use App\Models\ShoppingUser;
use Illuminate\Http\Request;
use App\Mail\MailOTPCustomer;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Validation\ValidationException;
use App\Models\Customer; // Oder User, je nach Setup
use App\Models\OtpToken; // Zum Speichern/Prüfen des OTP
use Illuminate\Support\Facades\Hash; // Zum Hashen des Tokens
class LoginController extends Controller
{
// Zeigt das Formular zur Eingabe der E-Mail an
public function showLoginForm()
{
//wenn als Berater eingeloggt, dann zum Login wechseln
if (Auth::guard('user')->check()) {
return redirect()->route('portal.change_login');
}
//wenn als Kunde eingeloggt, dann direkt zum Dashboard
if (Auth::guard('customers')->check()) {
return redirect()->route('portal.dashboard');
}
return view('portal.auth.login'); // Erstelle diese View
}
// Sendet das OTP
public function sendOtp(Request $request)
{
$request->validate(['email' => 'required|email']);
$email = $request->input('email');
// 1. Prüfen, ob die E-Mail im System bekannt ist über Kunden-Tabelle)
$customer = Customer::firstOrCreate(['email' => $email]); // Erstellt Kunden, wenn nicht vorhanden
if ($customer && $customer->language) {
\App::setLocale($customer->language);
}
//add user_shop_domain for back
$customer->user_shop_domain = session('user_shop_domain');
$customer->save();
// if (!$customerExists && !$orderExists) { // Oder nur eine Prüfung, je nach Logik
if (!$customer) { // Prüfung anhand des Customer-Models
throw ValidationException::withMessages([
'email' => __('auth.failed_customer'), // Generische Fehlermeldung
]);
}
// 2. Alten Token löschen (optional, aber empfohlen)
DB::table('otp_tokens')->where('email', $email)->delete();
// 3. OTP generieren (z.B. 6-stellige Zahl)
$otp = random_int(100000, 999999);
$expiresAt = Carbon::now()->addMinutes(10); // Gültigkeit z.B. 10 Minuten
// 4. OTP (gehasht!) speichern
DB::table('otp_tokens')->insert([
'email' => $email,
'token' => Hash::make((string)$otp), // WICHTIG: Token hashen!
'expires_at' => $expiresAt,
'created_at' => Carbon::now(),
]);
// 5. OTP per E-Mail senden (Notification oder Mailable verwenden)
try {
Mail::to($email)->locale(\App::getLocale())->send(new MailOTPCustomer($otp, $email));
} catch (\Exception $e) {
// Logge den Fehler
\Log::error('OTP Send Error: ' . $e->getMessage());
// Gib eine Fehlermeldung zurück, ohne Details preiszugeben
return back()->withErrors(['email' => 'Konnte E-Mail nicht senden. Bitte versuchen Sie es später erneut.'])->withInput();
}
// 6. Zum OTP-Eingabeformular weiterleiten (E-Mail in Session speichern oder als Parameter übergeben)
session(['otp_email' => $email]); // Explizit in Session speichern
return redirect()->route('portal.login.otp.form', ['email' => $email]); // E-Mail auch als Parameter übergeben
}
// Zeigt das Formular zur Eingabe des OTP an
public function showOtpForm(Request $request, $email = null, $otp = null)
{
//wenn als Berater eingeloggt, dann zum Login wechseln
if (Auth::guard('user')->check()) {
return redirect()->route('portal.change_login');
}
//wenn als Kunde eingeloggt, dann zum Dashboard wechseln
if (Auth::guard('customers')->check()) {
return redirect()->route('portal.dashboard');
}
// E-Mail aus der Session holen (oder als Request-Parameter erwarten)
if ($email) {
$email = $email;
} else {
$email = session('otp_email', $request->query('email'));
}
if (!$email) {
return redirect()->route('portal.login.form')->withErrors(['message' => 'Sitzung abgelaufen oder E-Mail fehlt.']);
}
// CSRF-Token regenerieren für neue Session
$request->session()->regenerateToken();
// Übergebe sowohl 'email' als auch 'otp' an die View
return view('portal.auth.verify-otp', ['email' => $email, 'otp_value' => $otp]); // Variable umbenannt zu otp_value für Klarheit
}
// Validiert das OTP und loggt den Kunden ein
public function verifyOtpAndLogin(Request $request)
{
$request->validate([
'email' => 'required|email',
'otp' => 'required|numeric|digits:6', // An die Länge deines OTPs anpassen
]);
$email = $request->input('email');
$otpInput = $request->input('otp');
// 1. Gespeicherten OTP-Eintrag finden
$otpRecord = DB::table('otp_tokens')->where('email', $email)->first();
// 2. Prüfen ob Eintrag existiert, nicht abgelaufen ist und das OTP (Hash) übereinstimmt
if (!$otpRecord || Carbon::now()->gt($otpRecord->expires_at) || !Hash::check($otpInput, $otpRecord->token)) {
// Ungültiges oder abgelaufenes OTP
DB::table('otp_tokens')->where('email', $email)->delete(); // Ungültigen Token löschen
return back()->withErrors(['otp' => 'Ungültiges oder abgelaufenes Einmalpasswort.'])->withInput(['email' => $email]);
}
// 3. Kunden-Objekt finden (basierend auf dem Provider-Model)
$customer = Customer::where('email', $email)->first(); // Oder User::where('email', $email)->where('role','customer')->first();
if (!$customer) {
// Sollte eigentlich nicht passieren, wenn sendOtp korrekt funktioniert hat
DB::table('otp_tokens')->where('email', $email)->delete();
return back()->withErrors(['otp' => __('auth.failed')])->withInput(['email' => $email]);
}
// 4. Kunden einloggen über den 'customers'-Guard
Auth::guard('customers')->login($customer); // Loggt den gefundenen Kunden ein
// 5. Explizite Session-Speicherung
$request->session()->save();
// 6. OTP-Eintrag löschen
DB::table('otp_tokens')->where('email', $email)->delete();
// 7. Session Token regenerieren (statt komplette Session)
$request->session()->regenerate();
// 8. customer DB aktualisieren
$shopping_user = ShoppingUser::where('billing_email', $email)->latest()->first();
if ($shopping_user) {
$data = [
'name' => $shopping_user->billing_firstname . ' ' . $shopping_user->billing_lastname,
'shopping_user_id' => $shopping_user->id,
'member_id' => $shopping_user->member_id,
'number' => $shopping_user->number,
'language' => session('locale') ?? 'de',
];
$customer->update($data);
} else {
$data = [
'name' => __('portal.guest'),
'shopping_user_id' => null,
'member_id' => null,
'number' => null,
'language' => session('locale') ?? 'de',
];
$customer->update($data);
}
// 10. Zum Kunden-Dashboard weiterleiten
return redirect()->intended(route('portal.dashboard')); // intended() leitet zur ursprünglich angefragten Seite weiter
}
// Logout für Kunden
public function logout(Request $request)
{
$url = Util::getMyMivitaShopUrl();
Auth::guard('customers')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect($url);
}
// Logout für Berater
public function logoutChange(Request $request)
{
//$url = Util::getMyMivitaShopUrl();
$user_shop_domain = session('user_shop_domain');
$locale = session('locale');
Auth::guard('user')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
session(['user_shop_domain' => $user_shop_domain]);
session(['locale' => $locale]);
return redirect()->route('portal.login.form');
}
}