Files
fotospiel-app/app/Http/Controllers/Auth/AuthenticatedSessionController.php

141 lines
3.7 KiB
PHP

<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\LoginRequest;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Route;
use Illuminate\Support\Str;
use Inertia\Inertia;
use Inertia\Response;
use Symfony\Component\HttpFoundation\Response as SymfonyResponse;
class AuthenticatedSessionController extends Controller
{
/**
* Show the login page.
*/
public function create(Request $request): Response
{
return Inertia::render('auth/login', [
'canResetPassword' => Route::has('password.request'),
'status' => $request->session()->get('status'),
]);
}
/**
* Handle an incoming authentication request.
*/
public function store(LoginRequest $request): SymfonyResponse
{
try {
$request->authenticate();
} catch (\Illuminate\Validation\ValidationException $e) {
$request->session()->flash('error', __('auth.login_failed'));
return redirect()->route('login')->withErrors($e->errors());
}
Log::info('Login attempt', ['login' => $request->login, 'authenticated' => Auth::check()]);
$request->session()->regenerate();
$request->session()->flash('success', __('auth.login_success'));
$user = Auth::user();
if ($user && $user->email_verified_at === null) {
return Inertia::location(route('verification.notice'));
}
$returnTo = $this->resolveReturnTo($request);
if ($returnTo !== null) {
return Inertia::location($returnTo);
}
return Inertia::location($this->defaultAdminPath());
}
/**
* Destroy an authenticated session.
*/
public function destroy(Request $request): RedirectResponse
{
Auth::guard('web')->logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('/');
}
private function resolveReturnTo(Request $request): ?string
{
$encoded = $request->string('return_to')->trim();
if ($encoded === '') {
return null;
}
return $this->decodeReturnTo($encoded, $request);
}
private function decodeReturnTo(string $value, Request $request): ?string
{
$candidate = $this->decodeBase64Url($value) ?? $value;
$candidate = trim($candidate);
if ($candidate === '') {
return null;
}
if (str_starts_with($candidate, '/')) {
return $candidate;
}
$targetHost = parse_url($candidate, PHP_URL_HOST);
$scheme = parse_url($candidate, PHP_URL_SCHEME);
if (! $scheme || ! $targetHost) {
return null;
}
$appHost = parse_url($request->getSchemeAndHttpHost(), PHP_URL_HOST);
if ($appHost && ! Str::endsWith($targetHost, $appHost)) {
return null;
}
return $candidate;
}
private function defaultAdminPath(): string
{
$base = rtrim(route('tenant.admin.app', absolute: false), '/');
if ($base === '') {
$base = '/event-admin';
}
return $base.'/events';
}
private function decodeBase64Url(string $value): ?string
{
if ($value === '') {
return null;
}
$padded = str_pad($value, strlen($value) + ((4 - (strlen($value) % 4)) % 4), '=');
$normalized = strtr($padded, '-_', '+/');
$decoded = base64_decode($normalized, true);
if ($decoded === false) {
return null;
}
return $decoded;
}
}