Verstehen Sie die interne Struktur des Laravel-Authentifizierungssystems und lernen Sie auf Quellcode-Ebene, wie Sie eigene Auth-Guards über die Interfaces Guard und StatefulGuard implementieren.
Die Facade Auth ist ein Proxy für Illuminate\Auth\AuthManager. Der AuthManager verwaltet mehrere Guards nach dem Driver-Muster und erzeugt bzw. cacht anhand von config/auth.php die passende Guard-Instanz.
resolve() liest den driver-Key aus dem guards-Array in config/auth.php und ruft die zugehörige Factory-Closure auf. Die eingebauten Treiber session und token sind auf dieselbe Weise registriert.
Unterschied zwischen Guard- und StatefulGuard-Interface
Ein Auth-Guard muss mindestens Illuminate\Contracts\Auth\Guard implementieren. Wenn Sie eine Sitzung aufrechterhalten wollen, implementieren Sie StatefulGuard.
Guard-Interface (Illuminate\Contracts\Auth\Guard)
interface Guard{ // Ist ein authentifizierter Nutzer vorhanden? public function check(); // Handelt es sich um einen Gast (unauthentifiziert)? public function guest(); // Aktuellen authentifizierten Nutzer zurückgeben (null bei Gast) public function user(); // ID des aktuellen Nutzers zurückgeben public function id(); // Prüfen, ob die Credentials gültig sind (ohne Login) public function validate(array $credentials = []); // Ist ein Nutzer gesetzt (auch ohne Login via setUser injizierbar)? public function hasUser(); // Nutzer manuell setzen public function setUser(Authenticatable $user);}
StatefulGuard erbt von Guard und ergänzt Methoden zur Sitzungshaltung via Session/Cookies.
interface StatefulGuard extends Guard{ // Credentials prüfen und einloggen (mit remember-Flag) public function attempt(array $credentials = [], $remember = false); // Nur für einen Request authentifizieren, ohne Session zu speichern public function once(array $credentials = []); // Eine Nutzerinstanz direkt einloggen public function login(Authenticatable $user, $remember = false); // Per ID einloggen public function loginUsingId($id, $remember = false); // Per ID nur für einen Request authentifizieren public function onceUsingId($id); // Prüfen, ob per "Angemeldet bleiben"-Cookie eingeloggt wurde public function viaRemember(); // Ausloggen public function logout();}
Für Guards, die keine Session benötigen — z. B. API-Auth oder eigene Tokens —, reicht Guard. Für Admin-Logins mit Session implementieren Sie StatefulGuard.
Die Methoden check(), guest(), id(), hasUser() des Guard-Interfaces sind fast immer gleich. Laravel bietet daher den Trait Illuminate\Auth\GuardHelpers. Damit müssen Sie nur user() und validate() implementieren.
// Standardimplementierung aus GuardHelpers (Auszug)trait GuardHelpers{ protected $user; public function check(): bool { return ! is_null($this->user()); } public function guest(): bool { return ! $this->check(); } public function id(): mixed { return $this->user()?->getAuthIdentifier(); } public function hasUser(): bool { return ! is_null($this->user); } public function setUser(Authenticatable $user): static { $this->user = $user; return $this; }}
In Anlehnung an TokenGuard implementieren wir einen einfachen API-Token-Guard. Er liest das Token aus Header oder Query und löst den Nutzer über UserProvider auf.
1
Guard-Klasse anlegen
Legen Sie die Klasse unter app/Auth an.
<?phpnamespace App\Auth;use Illuminate\Auth\GuardHelpers;use Illuminate\Contracts\Auth\Guard;use Illuminate\Contracts\Auth\UserProvider;use Illuminate\Http\Request;class ApiTokenGuard implements Guard{ use GuardHelpers; protected Request $request; public function __construct(UserProvider $provider, Request $request) { $this->provider = $provider; $this->request = $request; } /** * Aktuellen authentifizierten Nutzer zurückgeben */ public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { // Gecachten Nutzer zurückgeben, falls vorhanden if (! is_null($this->user)) { return $this->user; } $token = $this->getTokenForRequest(); if (empty($token)) { return null; } // Nutzer über UserProvider laden $this->user = $this->provider->retrieveByCredentials([ 'api_token' => $token, ]); return $this->user; } /** * Credentials nur validieren (kein Login) */ public function validate(array $credentials = []): bool { if (empty($credentials['api_token'])) { return false; } return (bool) $this->provider->retrieveByCredentials($credentials); } /** * Token aus dem Request holen * * Reihenfolge: Bearer-Header → Query-Parameter → Request-Body */ protected function getTokenForRequest(): ?string { $token = $this->request->bearerToken(); if (empty($token)) { $token = $this->request->query('api_token'); } if (empty($token)) { $token = $this->request->input('api_token'); } return $token ?: null; } /** * Request austauschen */ public function setRequest(Request $request): static { $this->request = $request; return $this; }}
2
Guard im Service Provider registrieren
Registrieren Sie den Guard im boot() des AppServiceProvider per Auth::extend().
<?phpnamespace App\Providers;use App\Auth\ApiTokenGuard;use Illuminate\Contracts\Foundation\Application;use Illuminate\Support\Facades\Auth;use Illuminate\Support\ServiceProvider;class AppServiceProvider extends ServiceProvider{ public function boot(): void { Auth::extend('api-token', function (Application $app, string $name, array $config) { // Provider aus der Config über Auth::createUserProvider() auflösen $provider = Auth::createUserProvider($config['provider'] ?? 'users'); return new ApiTokenGuard($provider, $app->make('request')); }); }}
Auth::createUserProvider() liest providers aus config/auth.php und gibt die passende UserProvider-Instanz zurück. Solange Sie keinen eigenen Provider bauen, erhalten Sie damit den Standard-EloquentUserProvider.
3
Guard in config/auth.php konfigurieren
Ergänzen Sie den Guard in config/auth.php.
'guards' => [ 'web' => [ 'driver' => 'session', 'provider' => 'users', ], // Ergänzter eigener Guard 'api' => [ 'driver' => 'api-token', // Muss dem ersten Argument von Auth::extend() entsprechen 'provider' => 'users', ],],
4
Guard auf Routen anwenden
Übergeben Sie den Guard-Namen an die auth-Middleware.
Ein per Auth::viaRequest() definierter Guard nutzt keinen UserProvider; Provider-Methoden wie retrieveById() funktionieren nicht. Für Produktion empfehlen wir klassenbasierte Guards per Auth::extend().
Wenn Nutzerinformationen nicht aus der Datenbank stammen (externe API, LDAP …), implementieren Sie Illuminate\Contracts\Auth\UserProvider.
<?phpnamespace App\Auth;use App\Models\User;use Illuminate\Contracts\Auth\Authenticatable;use Illuminate\Contracts\Auth\UserProvider;class ApiUserProvider implements UserProvider{ public function __construct( protected string $apiBaseUrl, protected string $model = User::class, ) {} /** * Nutzer per ID laden */ public function retrieveById(mixed $identifier): ?Authenticatable { return ($this->model)::find($identifier); } /** * Nutzer über "Angemeldet bleiben"-Token laden * Für Guards ohne Session reicht null */ public function retrieveByToken(mixed $identifier, string $token): ?Authenticatable { return null; } /** * "Angemeldet bleiben"-Token aktualisieren * Für Guards ohne Session leer lassen */ public function updateRememberToken(Authenticatable $user, string $token): void {} /** * Nutzer per Credentials laden * Wird von validate() und user() des Guards aufgerufen */ public function retrieveByCredentials(array $credentials): ?Authenticatable { if (empty($credentials['api_token'])) { return null; } // Beispiel: Token an externer API prüfen und Nutzerinfo holen $response = \Illuminate\Support\Facades\Http::withToken($credentials['api_token']) ->get("{$this->apiBaseUrl}/auth/me"); if (! $response->successful()) { return null; } $data = $response->json(); // Mit lokalem Nutzer verknüpfen oder Modell dynamisch anlegen return User::firstOrCreate( ['external_id' => $data['id']], ['name' => $data['name'], 'email' => $data['email']], ); } /** * Credentials des geladenen Nutzers prüfen * Bei Token-Auth genügt true, wenn retrieveByCredentials erfolgreich war */ public function validateCredentials(Authenticatable $user, array $credentials): bool { return true; } /** * Muss das Passwort neu gehasht werden? * Bei Token-Auth immer false */ public function rehashPasswordIfRequired(Authenticatable $user, array $credentials, bool $force = false): void {}}
Beispiel für einen Guard, der einen externen JWT-Auth-Dienst nutzt.
<?phpnamespace App\Auth;use App\Models\User;use Illuminate\Auth\GuardHelpers;use Illuminate\Contracts\Auth\Guard;use Illuminate\Contracts\Auth\UserProvider;use Illuminate\Http\Request;use Illuminate\Support\Facades\Http;class JwtGuard implements Guard{ use GuardHelpers; protected Request $request; protected ?array $payload = null; public function __construct(UserProvider $provider, Request $request) { $this->provider = $provider; $this->request = $request; } public function user(): ?\Illuminate\Contracts\Auth\Authenticatable { if (! is_null($this->user)) { return $this->user; } $token = $this->request->bearerToken(); if (empty($token)) { return null; } // JWT beim externen Dienst prüfen $payload = $this->verifyToken($token); if (is_null($payload)) { return null; } $this->payload = $payload; $this->user = $this->provider->retrieveById($payload['sub']); return $this->user; } public function validate(array $credentials = []): bool { if (empty($credentials['token'])) { return false; } return ! is_null($this->verifyToken($credentials['token'])); } /** * JWT prüfen und Payload zurückgeben */ protected function verifyToken(string $token): ?array { $response = Http::withToken($token) ->get(config('services.auth.verify_url')); if (! $response->successful()) { return null; } return $response->json(); } /** * Validiertes JWT-Payload liefern */ public function payload(): ?array { return $this->payload; }}
Registrierung im AppServiceProvider:
Auth::extend('jwt', function (Application $app, string $name, array $config) { return new \App\Auth\JwtGuard( Auth::createUserProvider($config['provider'] ?? 'users'), $app->make('request'), );});
Sie können auch guard-spezifische Methoden nutzen: Auth::guard('jwt')->payload(). Auth::guard() liefert die Guard-Instanz selbst — daher sind auch Methoden außerhalb des Interfaces erreichbar.