Ein eigener Auth-Driver in Laravel 4

Laravel 4 bringt von Haus aus zwei Auth-Driver mit: Database und Eloquent. Damit sind die Datenbanken, für die es PDO-Treiber gibt, gut abgedeckt. Möchte man einen User jedoch gegen andere Datenbanken, z.B. MongoDB, oder vielleicht gegen einen Webservice etc. authentifizieren, muß man selbst Hand anlegen. Da sich die Verwendung eines eigenen Auth-Drivers in Laravel 4 gegenüber Laravel 3 geändert hat, möchte ich die Funktionsweise vorstellen.

Konfiguration

Zuerst muß man Laravel mitteilen, welche Treiber man verwenden möchte. Dies passiert in der Datei app/config/auth.php. Dort finden wir die Zeile

'driver' => 'eloquent',

 
Diese müssen wir ändern und unseren eigenen Treiber angeben. In diesem Artikel soll der Name des Treibers example sein. Daher ändern wir die Zeile wie folgt:

'driver' => 'example',

 
Das ist natürlich noch lange nicht hinreichend. Laravel wird sich – völlig zu Recht – beschweren, daß es damit nichts anfangen kann. Wir müssen natürlich auch noch bekannt geben, wie man an den Treiber example herankommt. Dies passiert in der Datei app/start/global.php. Dort wird einfach folgender Block eingefügt:

Auth::extend('example', function($app) {
    $provider =  new \Example\Auth\ExampleUserProvider();

    return new \Illuminate\Auth\Guard($provider, $app['session']);
});

Der UserProvider

Die Klasse ExampleUserProvider müssen wir natürlich auch implementieren und damit kommen wir zum eigentlichen Kern des eigenen Auth-Drivers. Eine mögliche Implementierung sieht so aus:

<?php

namespace Example\Auth;

use Illuminate\Auth\UserProviderInterface,
    Illuminate\Auth\GenericUser,
    Example\Domain\User\Service\UserService,
    Example\Domain\User\Entity\User;

class ExampleUserProvider
    implements UserProviderInterface
{
    /**
    * @var UserService
    */
    private $userService;

    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    } 

    /**
     * Retrieve a user by their unique identifier.
     *
     * @param  mixed  $identifier
     *
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveByID($identifier)
    {
        /** @var User $user  */
        $user = $this->userService->findUserByUserIdentifier($identifier);

        if (!$user instanceof User) {
            return false;
        }

        return new GenericUser([
            'id'       => $user->getUserIdentifier(),
            'username' => $user->getUserName()
        ]);
    }

    /**
     * Retrieve a user by the given credentials.
     *
     * @param  array  $credentials
     *
     * @return \Illuminate\Auth\UserInterface|null
     */
    public function retrieveByCredentials(array $credentials)
    {
        /** @var User $user  */
        $user = $this->userService->findUserByUserName($credentials['username']);

        if (!$user instanceof User) {
            return false;
        }

        return new GenericUser([
            'id'       => $user->getUserIdentifier(),
            'username' => $user->getUserName()
        ]);
    }

    /**
     * Validate a user against the given credentials.
     *
     * @param \Illuminate\Auth\UserInterface $user
     * @param  array  $credentials
     *
     * @return bool
     */
     public function validateCredentials(\Illuminate\Auth\UserInterface $user, array $credentials)
     {
         $validated = $this->userService->validateUserCredentials(
             $credentials['username'],
             $credentials['password']
         );

         $validated = $validated && $user->userName = $credentials['username'];

         return $validated;
     }
}

 
In Laravel 4 muß ein UserProvider das UserProviderInterface und damit die Methoden

  • retrieveByID($id),
  • retrieveByCredentials($credentials) und
  • validateCredentials($user, $credentials)

implementieren.

Das User-Objekt

Mit Auth::user() kann man auf die Daten des eingeloggten Users zugreifen. Laravel speichert in der Session jedoch nur die ID. Wollen wir auf die anderen Daten des eingeloggten Users zugreifen, müssen diese erst von der Datenbank oder einer anderen Quelle bezogen werden. Die Aufgabe übernimmt die Methode retrieveById($id).

retrieveById($id)

Als Parameter wird eine ID übergeben. Dies kann ein Integer, ein String oder aber auch ein anderer Datentyp sein.

Als Rückgabe wird ein Objekt erwartet, welches das Interface UserInterface implementiert. Im einfachsten Fall ist dies, wie im Beispiel, der mitgelieferte GenericUser. Das zurückgegebene Objekt muß unbedingt die Property id haben, denn diese wird in der Session gespeichert.

Die Authentifizierung

In Laravel 4 erfolgt die Authentifizierung, die mit Auth::attempt($credentials) angestoßen wird, in zwei Schritten. Im ersten Schritt wird mit retrieveByCredentials($credentials) ein User gesucht, welcher die Credentials erfüllt. Im zweiten Schritt wird mit validateCredentials($user, $credentials) geprüft, ob das im ersten Schritt zurückgegebene Objekt zu den Credentials paßt.

Das mag auf den ersten Blick doppelt gemoppelt erscheinen, ergibt aber durchaus Sinn. Nicht immer besteht die Möglichkeit, nach Username und Passwort zu suchen. Im obigen Beispiel steht nur die Suche anhand des Nutzernamens zur Verfügung. Im mitgelieferten DatabaseUserProvider wird der entsprechende Nutzer nur anhand des Passworts gesucht. In beiden Fällen besteht also die Notwendigkeit zu prüfen, ob die andere Angabe auch zu dem Nutzer paßt. Außerdem ist so einfacher zu testen.

retrieveByCredentials($credentials)

Als Parameter wird ein Array $credentials übergeben. Typischerweise sind hier die Schlüssel username und password enthalten. Im Prinzip ist es aber dem Entwickler überlassen, welche Daten hier übergeben werden. Wichtig ist nur, daß man damit an die gewünschten Daten kommt.

Zurückgegeben wird auch hier ein Objekt, welches das Interface UserInterface implementiert. Das ist im einfachsten Fall der GenericUser.

validateCredentials($user, $credentials)

Als Parameter werden hier ein Objekt $user, welches das Interface UserInterface implementiert, sowie ein Array $credentials übergeben.

Als Rückgabe wird true oder false erwartet, je nachdem, ob $user und $credentials zusammenpassen oder nicht.

Zusammenfassung

Das Implementieren eines eigenen Auth-Drivers in Laravel 4 ist kein Hexenwerk. Es muß ein UserProvider mit drei Methoden implementiert werden, dieser muß dem System bekannt gemacht werden und schlußendlich muß man festlegen, daß man diesen Treiber verwenden will.

Tags: ,

Trackbacks/Pingbacks

  1. Write Your Own Auth-Driver for Laravel 4 | www.karlvalentin.de - 27. März 2013

    […] of some request I translated my post Ein eigener Auth-Driver in Laravel 4. Enjoy […]

Schreib einen Kommentar!