Аннулирование сессий на других устройствах в Laravel

Источник: «Invalidating sessions on other devices on Laravel»
Laravel предоставляет способ аннулирования и выхода из сеансов активного пользователя на других устройствах без аннулирования сеанса на текущем устройстве.

Недавно у меня украли мобильный телефон, и я понял, как много приложений не имеют функции контроля сеанса. Я не мог выйти из системы с этого устройства.

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

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

Аннулирование сеансов на других устройствах

Чтобы аннулировать сессию пользователя на всех устройствах, кроме текущего, необходимо вызвать метод Auth::logoutOtherDevices. Он требует от пользователя подтверждения пароля.

Это важно, поскольку если пользователь потерял или у него украли мобильный телефон, вы не можете позволить кому-то выйти из всех сессий, использующих это устройство.

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($currentPassword);

Чтобы метод logoutOtherDevices работал, Laravel предоставляет Illuminate\Session\Middleware\AuthenticateSession middleware, которое обнаруживает изменение хэша пароля, немедленно выводит пользователя из системы и запускает событие Illuminate\Auth\Events\CurrentDeviceLogout.

По умолчанию middleware AuthenticateSession может быть присоединено к маршруту с использованием псевдонима middleware маршрута auth.session, как определено в HTTP ядре приложения. Официальная документация Laravel

routes/web.php:

Route::middleware(['auth', 'auth.session'])->group(function () {
Route::get('/', function () {
// ...
});
});

Тогда вы, возможно, уже думаете, что делает logoutOtherDevices. Это повторное хэширование пароля. Хм, но меняется ли хэш даже при использовании одного и того же пароля? Да, меняется!

Аннулирование сессии определённого устройства

Это возможно, но вы должны управлять сессиями с помощью драйвера базы данных. Это позволяет запрашивать сессии и отображать список, чтобы пользователь мог выбрать конкретную сессию для аннулирования.

Драйверу базы данных нужна таблица. Вы можете использовать команду artisan session:table для создания такой миграции.

php artisan session:table

php artisan migrate

Установите драйвер в файле config/session.php в качестве базы данных:

//...
'driver' => env('SESSION_DRIVER', 'database')
//...

Или через атрибут SESSION_DRIVER в env-файле:

SESSION_DRIVER=database

Затем создайте модель для таблицы сессий:

php artisan make:model Session

Создайте отношения:

app/Models/Session.php:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Session extends Model
{
public $incrementing = false;

public function user(): BelongsTo
{
return $this->belongsTo(User::class);
}
}

app/Models/User.php:

namespace App\Models;

//...
use Illuminate\Database\Eloquent\Relations\HasMany;

class User extends Authenticatable
{
//...
public function sessions(): HasMany
{
return $this->hasMany(Session::class);
}
}

Теперь вы можете составить список сеансов:

$user = auth()->user();

$sessions = $user->sessions()
->select('id', 'ip_address', 'user_agent', 'last_activity')
->get();

dump($sessions->toArray());

Пример того, как это должно выглядеть:

array:3 [// routes/web.php:18
0 => array:4 [
"id" => "J9KBJgsqKWRu4JGhNpTF73EBhGXD9FneIR2vzEqX"
"ip_address" => "217.240.75.140"
"user_agent" => "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) ..."
"last_activity" => 1688043153
]
1 => array:4 [
"id" => "mfmRbbeR803hPpi0uLlPYtWaahqgw6CglEu5UMv7"
"ip_address" => "21.51.178.175"
"user_agent" => "Mozilla/5.0 (iPhone; CPU iPhone OS 11_6_9; like Mac OS X) ..."
"last_activity" => 1688043136
]
2 => array:4 [
"id" => "VCkIFZN0zjKq808gvps7haz8XzOkOjnxVlZQifwe"
"ip_address" => "25.31.180.18"
"user_agent" => "Mozilla / 5.0 (compatible; MSIE 8.0; Windows; U; Windows NT 10.0; WOW64; en-US Trident / 4.0)"
"last_activity" => 1688043145
]
]

Наконец, чтобы уничтожить конкретную сессию, необходимо удалить её из базы данных. В приведённом ниже примере мы отсоединяем iPhone:

$user->sessions()
->where('id', 'mfmRbbeR803hPpi0uLlPYtWaahqgw6CglEu5UMv7')
->delete();

В заключение

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

Дополнительные материалы

Предыдущая Статья

Как исправить ошибку 419 Page Expired/CSRF token mismatch

Следующая Статья

Laravel Folio