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

Защита маршрутов

На данный момент даже неавторизированные пользователи имеют доступ к маршруту /dashboard. Маршруты Vue можно защитить методом, похожим на то, как это делается с помощью middleware в Laravel.

Первое, что вам нужно знать, это то, что мы можем прикреплять произвольные мета-данные к маршрутам через объект meta. Мы будем использовать этот объект для того, что пометить маршрут /dashboard как защищенный. Откройте файл routes.js и отредактируйте маршрут /dashboard следующим образом:

{
    path: '/dashboard',
    component: require('./views/Dashboard.vue'),
    meta: { middlewareAuth: true }
}

Затем мы можем применить к маршрутизатору глобальный метод beforeEach(), который позволяет выполнять любые проверки и действия до того, как маршрут будет загружен - прямо как middleware в Laravel.

Удалите весь код после массива routes и вставьте на его место вот это:

const router = new VueRouter({
    routes
});

router.beforeEach((to, from, next) => {
    if (to.matched.some(record => record.meta.middlewareAuth)) {                
        if (!auth.check()) {
            next({
                path: '/login',
                query: { redirect: to.fullPath }
            });

            return;
        }
    }

    next();
})

export default router;

Вы видите отредактированный пример из документации vue-router. Ознакомьтесь с оригиналом в документации, чтобы понять этот код лучше. Если вкратце, то мы просто определяем текущий маршрут и проверяем есть ли у него атрибут meta.requiresAuth в мета-данных и равно ли его значение true. Если значение равно true, это означает, что маршрут требует авторизации для доступа и если пользователь неавторизирован, мы перенаправляем его на страницу входа. Теперь обновите страницу и нажмите на ссылку Dashboard - вас должно перекинуть на страницу /login. Все остальные ссылки должны работать как и прежде.

Нам также надо запретить доступ к маршруту /login авторизированным пользователям. Сейчас мы просто скрываем ссылку, но ничто не мешает пользователю ввести путь напрямую в строку адреса браузера. Уверен, что вы сможете справиться с этой задачей самостоятельно. Отвлекитесь ненадолго от чтения и займитесь воплощением данного функционала в жизнь.

Восстанавливаем данные об аутентификации при загрузке страницы

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

Откройте файл auth.js. Мы будем считывать данные из локального хранилища в конструкторе (сейчас же мы просто задаем null переменным).

constructor () {
    this.token = window.localStorage.getItem('token');

    let userData = window.localStorage.getItem('user');
    this.user = userData ? JSON.parse(userData) : null;

    if (this.token) {
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.token;
    }
}

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

export default Auth;

И соответствующие изменения в файле app.js:

import Auth from './auth.js';

window.auth = new Auth();

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

Думаю, нам нужно добавить защищенный маршрут в API, который будет возвращать объект авторизированного пользователя исходя из запроса. Если токен в заголовке AJAX запроса окажется неверным, мы разлогиним пользователя на стороне frontend'а. Если токен верный - мы просто обновим информацию о пользователе на случай, если она изменилась на сервере или была изменена в локальном хранилище.

Начнем с frontend'а. Отредактируйте конструктор класса Auth и вызовите новый метод getUser() в том случае, если в локальном хранилище был сохранен токен:

if (this.token) {
    axios.defaults.headers.common['Authorization'] = 'Bearer ' + this.token;

    this.getUser();
}

Этот метод будет просто делать AJAX запрос и обновлять свойство класса user в случае успеха, или разлогинивать пользователя в случае ответа со статусом 401 "Unauthorized".

getUser() {
    axios.get('/api/get-user')
        .then(({data}) => {
            this.user = data;
        })
        .catch(({response}) => {
            if (response.status === 401) {
                this.logout();
            }
        });
}

Теперь backend. Откройте routes/api.php и добавьте защищенный маршрут /api/get-user:

...
Route::middleware('auth:api')->group(function () {
    Route::post('/logout', 'API\AuthController@logout');
    Route::get('/get-user', 'API\AuthController@getUser');
});

Что касается метода в контроллере, то он будет очень простым. Мы просто будем возвращать объект авторизированного пользователя.

public function getUser()
{
    return auth()->user();
}

Для проверки авторизируйтесь, задайте левый токен вручную выполнив команду auth.login('token', {}); в консоли браузера, затем обновите страницу. Вас должно разлогинить вскоре после того, как загрузится страница.

Делаем запросы к API

Поздравляю, с аутентификацией наконец-то покончено! Скоро вы сможете приступить к разработке своего приложения. Но сначала, давайте решим проблему, которую я упомянул в предыдущей части урока - нам нужно разлогинивать пользователей после каждого запроса к API, который возвращает ответ со статусом 401 (пользователь может выполнить auth.login('token', {}); уже после изначальной проверки при загрузке страницы). Чтобы это сделать, нам нужно добавлять следующий кусочек к каждому запросу axios:

.catch(({response}) => {
    if (response.status === 401) {
        this.logout();
    }
});

Не очень удобно, правда? Вместо этого давайте напишем метод-обертку для axios, в котором будем добавлять этот кусок ко всем запросам. Мы будем использовать JS Promise (обещание) (если вы не знаете, что это такое - почитайте в интернете). Создайте новый файл resources/assets/js/api.js:

class Api {
    constructor () {}
}

export default Api;

Дальше создайте глобальный объект этого класса в файле app.js. Ничего нового. Заметьте, что важно поместить строчку window.api = new Api(); ПЕРЕД строкой window.auth = new Auth();, иначе будет выдаваться ошибка.

import Api from './api.js';

window.api = new Api();

Добавьте новый метод call в класс Api:

call (requestType, url, data = null) {
    return new Promise((resolve, reject) => {
        axios[requestType](url, data)
            .then(response => {
                resolve(response);
            })
            .catch(({response}) => {
                if (response.status === 401) {
                    auth.logout();
                }

                reject(response);
            });
    });
}

Этот метод делает обычный AJAX запрос с axios, но при этом добавляет логику по-умолчанию для метода catch. Вы можете использовать этот метод для всех своих запросов к API вместо использования axios напрямую. Вы можете использовать методы catch и call так же, как и с axios, при этом условие на проверку кода ответа 401 не будет перезаписано. Отредактируем метод getUser в файле auth.js, после чего все должно работать как и прежде:

getUser() {
    api.call('get', '/api/get-user')
        .then(({data}) => {
            this.user = data;
        });
}

Заключение

Все готово для того, чтобы начать разрабатывать непосредственно приложение. В реальном проекте вы, скорее всего, организуете ваши JavaScript и Vue файлы немного по-другому. То же можно сказать и про backend. Рекомендую ознакомиться с документацией vue-router, чтобы знать, какие у него еще есть возможности, ибо мы затронули только самое основное. Также вам может пригодиться Vuex, хотя это уже более сложная технология.