Аутентификация

Введение

Laravel позволяет сделать аутентификацию очень простой. Фактически, почти всё уже готово к использованию «из коробки». Настройки аутентификации находятся в файле config/auth.php, который содержит несколько хорошо документированных опций для настройки механизма аутентификации.

По умолчанию, Laravel использует модель App\User в каталоге app. Эта модель может использоваться вместе с драйвером аутентификации на базе Eloquent.

В Laravel уже включены все необходимые миграции для создания аутентификации, но при самостоятельном создании схемы БД не забудьте про два обязательных поля в таблице user (или аналогичной):

  • поле с паролем длиной минимум в 60 символов,
  • поле remember_token для хранения идентификаторов «запомнить меня» длиной в 100 символов (можно создать методом $table->rememberToken(); в миграции).

Если ваше приложение не использует Eloquent, вы можете использовать драйвер аутентификации database, который работает через конструктор запросов.

Аутентификация пользователей

В Laravel уже есть два контроллера, относящиеся к механизму аутентификации. Контроллер AuthController обрабатывает регистрацию пользователей и вход в приложение, тогда как контроллер PasswordController содержит механизмы для сброса забытых паролей у существующих пользователей.

Каждый из этих контроллеров использует трейты для подключения необходимых методов. Как правило, вам не нужно менять код этих контроллеров. Шаблоны, используемые этими контроллерами, находятся в каталоге resources/views/auth и вы можете свободно изменять их так, как вам нужно.

Регистрация пользователей

Для редактирования набора полей формы, которую заполняет пользователь при регистрации, необходимо изменить класс App\Services\Registrar, который так же отвечает за валидацию введённых данных и создание новых пользователей.

Метод validator класса Registrar содержит правила валидации для новых пользователей, тогда как метод create отвечает непосредственно за создание новой записи о пользователе в БД вашего приложения. Вы можете изменять код этих методов при необходимости. Registrar вызывается в контроллере AuthController через метод, находящийся в трейте AuthenticatesAndRegistersUsers.

Ручная аутентификация

Если вы не хотите использовать механизм, предоставляемый контроллером AuthController, то вы должны использовать сервис аутентификации напрямую. Не волнуйтесь, это не сложно! Для начала, давайте посмотрим на метод attempt:

<?php namespace App\Http\Controllers;

use Auth;
use Illuminate\Routing\Controller;

class AuthController extends Controller {

    /**
     * Handle an authentication attempt.
     *
     * @return Response
     */
    public function authenticate()
    {
        if (Auth::attempt(['email' => $email, 'password' => $password]))
        {
            return redirect()->intended('dashboard');
        }
    }

}

Метод attempt принимает массив «ключ-значение» в качестве первого аргумента. Значение ключа password будет захэшировано. Другие значения массива используются для поиска пользователя в таблице БД. В примере выше, пользователь будет выбираться по полю email. Если пользователь будет найден, то хэшированный пароль из БД будет сравнён с хэшированным значение поля password из переданного массива. Если два этих хэша совпадут, то для пользователя будет создана новая аутентифицированная сессия.

Метод attempt возвращает true, если аутентификация прошла успешно, и false в противном случае.

Примечание: В примере выше, поле email не является обязательным, оно выбрано для примера. Вы должны использовать то название колонки, в котором хранится логин в приложении. Как правило, это «username».

Метод intended возвращает пользователя на тот адрес, доступ к которому он хотел получить, прежде чем его поймал фильтр аутентификации. В качестве параметра, в этот метод можно передать резервный адрес, если запрашиваемый адрес недоступен.

Аутентификация пользователя с дополнительными условиями

Вы можете добавить дополнительные условия в аутентификационный запрос:

if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1]))
{
    // Пользователь существует, не забанен и активен. 
}

Как узнать, что пользователь прошел аутентификацию?

Для проверки, аутентифицирован ли пользователь в вашем приложении, можно использовать метод check:

if (Auth::check())
{
    // Пользователь аутентифицирован...
}

Аутентификация и «запоминание» пользователя

Если вы хотите разрешить пользователям использовать механизм «запомнить меня», вы можете передать булево значение вторым аргументом в метод attempt, что позволит сохранить статус аутентификации пользователя либо навсегда, либо до тех пор, пока он сам не выйдет из приложения. Естественно, ваша табличка users должна содержать колонку remember_token, которая будет использоваться для хранения токена пользователя.

if (Auth::attempt(['email' => $email, 'password' => $password], $remember))
{
    // Пользователь будет «запомнен»...
}

Если вы «запоминаете» пользователя, то можете использовать метод viaRemember чтобы определить, был ли пользователь аутентифицирован с использованием этого механизма:

if (Auth::viaRemember())
{
    //
}

Аутентификация пользователя по ID

Для аутентификации пользователя по его ID существует метод loginUsingId:

Auth::loginUsingId(1);

Проверка прав пользователя без аутентификации

Метод validate позволяет проверить права пользователя без фактической аутентификации:

if (Auth::validate($credentials))
{
    //
}

Аутентификация пользователя на время выполнения текущего запроса

Метод once служит для аутентификация пользователя на время выполнения текущего запроса, при этом не используются сессия и куки:

if (Auth::once($credentials))
{
    //
}

Ручная аутентификация пользователя

Для принудительной аутентификации пользователя существует метод login:

Auth::login($user);

Это эквивалентно аутентификации с использованием метода attempt и передачей параметров пользователя.

Выход из приложения

Auth::logout();

Конечно, если вы используете встроенные контроллеры Laravel для аутентификации, то в них всё это уже реализовано.

События при аутентификации

При вызове метода attempt запускается событие auth.attempt. Если аутентификация прошла успешно и пользователь вошёл в приложение, будет запущено событие auth.login.

Получение аутентифицированного пользователя

Как только пользователь аутентифицирован, вы можете получить объект пользователя несколькими путями.

Во-первых, с помощью фасада Auth:

<?php namespace App\Http\Controllers;

use Illuminate\Routing\Controller;

class ProfileController extends Controller {

    /**
     * Update the user's profile.
     *
     * @return Response
     */
    public function updateProfile()
    {
        if (Auth::user())
        {
            // Auth::user() возвращает объект пользователя...
        }
    }

}

Во-вторых, используя метод user класса Illuminate\Http\Request:

<?php namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Illuminate\Routing\Controller;

class ProfileController extends Controller {

    /**
     * Update the user's profile.
     *
     * @return Response
     */
    public function updateProfile(Request $request)
    {
        if ($request->user())
        {
            // $request->user() возвращает объект пользователя...
        }
    }

}

В третьих, можно использовать мощь сервис-контейнера, указав в качестве аргумента в конструкторе или методе контракт Illuminate\Contracts\Auth\Authenticatable:

<?php namespace App\Http\Controllers;

use Illuminate\Routing\Controller;
use Illuminate\Contracts\Auth\Authenticatable;

class ProfileController extends Controller {

    /**
     * Update the user's profile.
     *
     * @return Response
     */
    public function updateProfile(Authenticatable $user)
    {
        // $user - это объект пользователя...
    }

}

Ограничение доступа к роутам

Вы можете использовать посредников (middleware) для ограничения доступа к роутам. В Laravel уже есть посредник auth, который находится в файле app\Http\Middleware\Authenticate.php. Всё, что вам нужно - указать его в описании нужного роута:

// Если роут описан как замыкание...

Route::get('profile', ['middleware' => 'auth', function()
{
    // Доступ разрешён только аутентифицированным пользователям...
}]);

// Или как контроллер...

Route::get('profile', ['middleware' => 'auth', 'uses' => 'ProfileController@show']);

Аутентификация на основе HTTP Basic

Аутентификация на основе HTTP Basic позволяет аутентифицировать пользователей быстро и без отдельной страницы входа. Для этого надо указать посредника auth.basic в описании нужного роута:

Защита роута при помощи HTTP Basic

Route::get('profile', ['middleware' => 'auth.basic', function()
{
    // Доступ разрешён только аутентифицированным пользователям...
}]);

По умолчанию, посредник basic использует поле email из таблицы пользователей в качестве идентификатора пользователя.

Настройка Stateless HTTP Basic фильтра

Так же можно использовать аутентификацию на основе HTTP Basic без создания сессии и идентификационной куки, что часто используется для аутентификации через API. Для этого нужно создать посредника, который будет вызывать метод onceBasic:

public function handle($request, Closure $next)
{
    return Auth::onceBasic() ?: $next($request);
}

Если вы используете PHP в режиме FastCGI, то аутентификация на основе HTTP Basic может не работать «из коробки». Решается эта проблема добавлением следующих строк в файл .htaccess:

RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

Напоминание и сброс пароля

Модель и таблица

Большинство веб-приложения позволяют пользователям сбросить забытый пароль. Вместо того, чтобы каждый раз изобретать велосипед, Laravel предоставляет удобный механизм для реализации этой возможности.

Для начала, удостоверьтесь, что ваша модель User реализует контракт Illuminate\Contracts\Auth\CanResetPassword в том случае, если вы не используете стандартную модель User, которая уже реализует этот контракт при помощи трейта Illuminate\Auth\Passwords\CanResetPassword.

Создание миграции для таблицы с напоминаниями паролей

Далее нужно создать таблицу, хранящую токены-напоминания для сброса пароля. Эта миграция уже включена в Laravel и находится в папке database/migrations. Поэтому всё, что вам нужно сделать, это выполнить команду:

php artisan migrate

Контроллер напоминания паролей

Laravel так же предоставляет контроллер Auth\PasswordController, который содержит всю логику для работы со сбросом паролей. Так же есть и начальные шаблоны! Шаблоны находятся в папке resources/views/auth и вы можете изменять их так, как вам нужно.

Пользователь получает письмо со ссылкой, обрабатываемой методом getReset в контроллере PasswordController. Это метод отображает форму, где пользователь указывает новый пароль. После этого пользователь автоматически аутентифицируется и перенаправляется на адрес /home. Вы можете задать свой адрес в свойстве redirectTo контроллера PasswordController:

protected $redirectTo = '/dashboard';

Примечание: По умолчанию, срок жизни токена ограничен одним часом. Вы можете изменить это, указав нужное время в опции reminder.expire в файле config/auth.php.

Аутентификация через социальные сети

В добавок к обычной аутентификации, с помощью форм и HTTP Basic, Laravel предоставляет простой и удобный механизм аутентификации через OAuth, используя Laravel Socialite. Socialite пока что поддерживает аутентификацию только через Facebook, Twitter, Google и GitHub.

Чтобы начать использовать Socialite, добавьте этот пакет в ваш файл composer.json:

"laravel/socialite": "~2.0"

После, зарегистрируйте провайдер Laravel\Socialite\SocialiteServiceProvider в файле config/app.php. Вы так же можете зарегистрировать фасад Socialize:

'Socialize' => 'Laravel\Socialite\Facades\Socialite',

Далее вам необходимо указать параметры для того сервиса OAuth, который вы используете. Это можно сделать в файле config/services.php. Пока доступно четыре сервиса: facebook, twitter, google и github. Пример:

'github' => [
    'client_id' => 'your-github-app-id',
    'client_secret' => 'your-github-app-secret',
    'redirect' => 'http://your-callback-url',
],

После этого нужно добавить два роута: один для перенаправления пользователя к провайдеру OAuth, второй для получения ответа от провайдера после аутентификации пользователя. Пример с использованием фасада Socialize:

public function redirectToProvider()
{
    return Socialize::with('github')->redirect();
}

public function handleProviderCallback()
{
    $user = Socialize::with('github')->user();

    // $user->token;
}

Метод redirect выполнит перенаправление к провайдеру OAuth, а метод user получит информацию о пользователе из ответа провайдера OAuth. Перед перенаправлением, вы можете указать области доступа:

return Socialize::with('github')->scopes(['scope1', 'scope2'])->redirect();

Как только вы получите объект пользователя, можно получить пользовательские данные:

Получение данных пользователя

$user = Socialize::with('github')->user();

// Провайдеры, использующие OAuth v.2.0
$token = $user->token;

// Провайдеры, использующие OAuth v.1.0
$token = $user->token;
$tokenSecret = $user->tokenSecret;

// Все провайдеры
$user->getNickname();
$user->getName();
$user->getEmail();
$user->getAvatar();