Introduction
If you haven't heard of Laravel before, check it out - it's a modern PHP framework that makes it a breeze to develop web applications.
As part of Laravel, it includes an Authentication service which lets users login to your application. The Laravel Auth service is incredibly powerful, allowing you to configure different "guards" to protect different areas of your site - e.g. a user area & admin area. It's also very flexible as it allows you to use different user providers or drivers.
The user accounts for your application need to be stored somewhere - that might be in a local database under your control, or it could be a 3rd party authentication system delivered via an API. The authentication user providers in Laravel sit between your data source, and the core Laravel auth service. Out of the box, Laravel ships with two providers; one for Eloquent (the Laravel ORM), and one for direct database access - brilliant if your users are stored in your database. But what if they're not? What if you're using an API for authentication (e.g. OAuth)?
This is where customer user providers (sometimes also called drivers) come in. These let you provide an interface between your user authentication service and the Laravel functionality. They're easy to implement - so let's dive into some code (I'm assuming you're using the current release, Laravel 5.2):
Stage 1: Register your custom user provider
First off, you need to create a service provider, which will register your custom authentication user provider. If you've used service providers before, the following example should be quite easy to follow:
namespace App\Authentication;
use Auth;
use App\Authentication\UserProvider;
use Illuminate\Support\ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* Perform post-registration booting of services.
*
* @return void
*/
public function boot()
{
Auth::provider('our_provider', function($app, array $config) {
return new UserProvider();
});
}
/**
* Register bindings in the container.
*
* @return void
*/
public function register()
{
//
}
}
This simply registers your user provider / driver, making it usable in the config/auth.php
file via the our_provider
key. It also has a callback which returns an instance of App\Authentication\UserProvider()
(which we'll see shortly). Don't forget to register this service in your config/app.php
file (instructions here if you're unsure).
Stage 2: Update config to use new driver
Now we've registered our custom Laravel user provider / driver, we need to tell our site to use it. This is really simple - open up your config/auth.php
file and scroll down to the "providers" section, and simply update the driver name as shown:
'providers' => [
'users' => [
'driver' => 'our_provider',
],
],
That's it - your site is now setup to use the new driver. But before it's usable - we need to write some more code.
Stage 3: Create a user class
The authentication service needs to be able to handle users, so let's create a class to represent a user (if you were using the Eloquent driver, it would be your user model, e.g. App\Models\User
). This user class must implement the Illuminate\Contracts\Auth\Authenticatable
interface that ships with Laravel - this interface includes a number of methods that must be available in our user class - without them, the authentication service wouldn't function. Here is an example user class:
<?php
namespace App\Authentication;
use Illuminate\Contracts\Auth\Authenticatable;
class User implements Authenticatable
{
/**
* @return string
*/
public function getAuthIdentifierName()
{
// Return the name of unique identifier for the user (e.g. "id")
}
/**
* @return mixed
*/
public function getAuthIdentifier()
{
// Return the unique identifier for the user (e.g. their ID, 123)
}
/**
* @return string
*/
public function getAuthPassword()
{
// Returns the (hashed) password for the user
}
/**
* @return string
*/
public function getRememberToken()
{
// Return the token used for the "remember me" functionality
}
/**
* @param string $value
* @return void
*/
public function setRememberToken($value)
{
// Store a new token user for the "remember me" functionality
}
/**
* @return string
*/
public function getRememberTokenName()
{
// Return the name of the column / attribute used to store the "remember me" token
}
}
Exactly how you implement each of these methods will differ depending on how and where you store your users. If you're using a default Laravel installation, take a look at the default User model class - App\User
this ultimately implements the Illuminate\Contracts\Auth\Authenticatable
interface via the \Illuminate\Auth\Authenticatable
trait.
Stage 4: Create a UserProvider class
In stage 1, we had a callback function which returned an instance of App\Authentication\UserProvider
- this class is used to retrieve instances of our users - App\Authentication\User
. Like our User class, this also needs to implement an interface, this time it's Illuminate\Contracts\Auth\UserProvider
.
<php
namespace App\Authentication;
use Illuminate\Contracts\Auth\UserProvider as IlluminateUserProvider;
class UserProvider implements IlluminateUserProvider
{
/**
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier)
{
// Get and return a user by their unique identifier
}
/**
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token)
{
// Get and return a user by their unique identifier and "remember me" token
}
/**
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
* @return void
*/
public function updateRememberToken(Authenticatable $user, $token)
{
// Save the given "remember me" token for the given user
}
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials)
{
// Get and return a user by looking up the given credentials
}
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials)
{
// Check that given credentials belong to the given user
}
}
Again, I can't tell you how to implement these methods as it depends on how and where you're storing your users, but as an example, you might inject an API provider via the constructor, and then make API calls to get user data, apply it to an instance of our user class, then return it.
Wrapping up
With all of that implemented, your new custom user provider / driver for the Laravel authentication service should be working - all that remains is for you to test it.
You can access all of the example code in a Gist.
If you've got any questions, I'm @gbuckingham89 on Twitter.