Laravel 5.6 - Как аутентифицировать API с помощью сеансов для одной и той же папки SPA?

У меня есть React SPA в том же проекте Laravel. Вход в систему / регистрация / выход из системы и все другие представления js находятся в папке js и используют вызовы api axios для всех запросов POST/GET. Я хочу использовать веб-аутентификацию на основе сеанса Laravel по умолчанию для встроенного SPA, поскольку он находится в той же папке проекта и будет единственным клиентом javascript, имеющим к нему доступ. Этот api не должен быть открытым для публики, только для этого реагирующего приложения, и это SPA для скорости и хорошего взаимодействия с пользователем вместо полной перезагрузки страницы.

Я пробовал использовать Passport раньше и больше месяца я все еще не могу заставить его работать должным образом. Я не хочу иметь дело с токенами, токенами доступа, токенами обновления, отзывом токенов, CSRF и т. Д. Просто готовая простая аутентификация на основе сеанса Laravel, которая так легко работает в Интернете, но хочу, чтобы она работала в моем приложении для реагирования. Единственный файл лезвия - это index.blade.php, который включает реакцию app.js

Есть идеи, как это сделать?

ОБНОВЛЕНИЕ 1:

После реализации предложения @ceejayoz:

Вы должны добавить различные промежуточные программы Session / Cookie в app / Http / Kernel.php (например, \ Illuminate \ Session \ Middleware \ StartSession :: class) к маршрутам API.

Я добавил в $middlewareGroups.api, чтобы соответствовать web промежуточному программному обеспечению в app/Http/Kernel.php:

'api' => [
    'throttle:60,1',
    'bindings',
    // Newly added middleware to match web middleware
    \App\Http\Middleware\EncryptCookies::class
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
    \Illuminate\Session\Middleware\StartSession::class,
    \Illuminate\View\Middleware\ShareErrorsFromSession::class,
    \App\Http\Middleware\VerifyCsrfToken::class,
    \Illuminate\Routing\Middleware\SubstituteBindings::class,
],

Я понял, что возникли две проблемы:

  1. В таблице сеансов, даже если вы не вошли в систему, при загрузке домашней страницы приложения (или любой страницы) несколько сеансов вставляются в таблицу sessions. Не следует ли вставлять новый одиночный сеанс в эту таблицу только после входа пользователя в систему?
  2. После входа пользователя в систему, при обновлении страницы вручную в браузере и вызове защищенного маршрута я получаю 401 Unauthenticated, который указывает мне на этот метод в Illuminate/Auth/GuardHelpers.php:

    public function authenticate() {
        if (! is_null($user = $this->user())) {
            return $user;
        }
    
        throw new AuthenticationException; // throws this 401 exception on logged in page refresh when fetching data from private route
    }
    

Некоторые дополнительные примечания:

  • В config/auth.php я обновил guards.api.driver до session вместо token.
  • В routes/api.php у меня есть защищенные маршруты, завернутые в промежуточное ПО для аутентификации, например: Route::group(['middleware' => 'auth'], function() { PRIVATE ROUTES HERE }
  • В config/session.php у меня 'domain' => '.mydomain.com'
  • Я отправляю эти заголовки с каждым запросом api axios следующим образом:

    window.axios.defaults.headers.common['X-Requested-With'] = 'XMLHttpRequest';
    let token = document.head.querySelector('meta[name="csrf-token"]');
    window.axios.defaults.headers.common['X-CSRF-TOKEN'] = token.content;
    

Есть идеи, как исправить эти 2 проблемы?


person Wonka    schedule 15.01.2019    source источник
comment
Это выполнимо. Вы должны добавить различные промежуточные программы Session / Cookie в app/Http/Kernel.php (например, \Illuminate\Session\Middleware\StartSession::class) в маршруты API.   -  person ceejayoz    schedule 16.01.2019
comment
Если вы планируете использовать свои маршруты с префиксом /api, вы можете просто определить их в routes/web.php, а не в routes/api.php. Убедитесь, что вы включили auth промежуточное ПО. Затем вы можете поместить их в группу Route::group(['prefix' => 'api', 'middleware' => ['auth'],], function () {...   -  person ljubadr    schedule 16.01.2019
comment
@ceejayoz Это действительно очень умно, спасибо, что поделились! Это НАСТОЛЬКО проще, чем реализация Passport, что, я думаю, было бы излишним для моего варианта использования. Если вы опубликуете ответ, я приму его, так как он требует наименьшего количества рефакторинга. Спасибо за ваш комментарий!   -  person Wonka    schedule 16.01.2019
comment
@ljubadr Мне удалось оставить файл api.php как есть и не перемещать его в web.php, используя потрясающую технику ceejayoz. Просто нужно было обновить auth: api до auth, и это сработало. Спасибо за ваш комментарий!   -  person Wonka    schedule 16.01.2019
comment
Рад, что ты нашел решение!   -  person ljubadr    schedule 16.01.2019
comment
@ljubadr Я думал, что это сработало, но на самом деле нет, я добавил обновление с этой проблемой. Затем я попробовал ваш метод перемещения маршрутов в Интернет и использования комбинации промежуточного программного обеспечения prefix / auth, но все же обнаружил те же 2 проблемы в моем обновлении. Есть идеи, как действовать?   -  person Wonka    schedule 17.01.2019
comment
Не уверен, что вам также нужно web промежуточное ПО. Сессии создаются, даже если пользователь не вошел в систему.   -  person ljubadr    schedule 17.01.2019
comment
Я пробовал добавить его, но без разницы. Я думаю, что он применяется по умолчанию к веб-маршрутам. Я видел здесь статью для laravel 5.3 josephsilber.com/posts/2016/07/10/, пункт 1, не уверен, что это все еще применимо к этой версии laravel, поскольку запросы ajax работают до тех пор, пока мы не обновим страницу, затем он становится неаутентифицированным только при получении защищенных маршрутов. Pinging @ joseph-silber, так как это его статья, и он может узнать больше ...   -  person Wonka    schedule 17.01.2019
comment
вы правы, web промежуточное ПО применяется к маршрутам web.php. Возможно, вы можете попробовать отладить сеанс, проверьте этот вопрос. Если вы звоните index.blade.php, возможно, распечатайте адрес электронной почты пользователя на странице и посмотрите, сохраняется ли он после перезагрузки страницы и не потерян ли сеанс. Все ли вызовы ajax (GET, POST, ...) возвращают 401 после обновления страницы?   -  person ljubadr    schedule 18.01.2019
comment
Да, поэтому после обновления страницы любые защищенные аутентификацией вызовы ajax возвращают 401 (но они работают до обновления без проблем). Когда я распечатал Auth::user()->email в лезвии, он показывает no auth email до и после входа в систему, при обновлении страницы он показывает адрес электронной почты пользователя, но получаю ошибку 401 ajax, затем обновляю страницу снова и показывает 'no auth email', и на все будущее обновляет сообщение «no auth email» и постоянно 401 для вызовов ajax для маршрутов, защищенных auth, незащищенные маршруты всегда загружают данные без ошибок через ajax.   -  person Wonka    schedule 18.01.2019
comment
@ljubadr Хорошие новости! Я понял это, основываясь на вашем связанном вопросе, но не на этих переменных. Итак, в config/session.php у меня была последняя переменная 'same_site' => 'strict' после изменения ее на 'same_site' => null ошибка 401 исчезла, и все работает отлично. Я хотел бы наградить вас наградой, так как вы очень помогли мне в этом и указали мне правильное направление. Я сделаю это, как только вы опубликуете ответ относительно проверки и изменения переменной config/session.php. Я очень ценю это, большое вам спасибо!   -  person Wonka    schedule 18.01.2019
comment
Привет, я рад, что ты это понял. Я только что проверил один из своих проектов и same_site => null. Думаю, ты когда-то его изменил :) Скоро добавлю ответ   -  person ljubadr    schedule 18.01.2019
comment
Поскольку вы обслуживаете свой app.js из своего blade-сервера в производственной среде (без CORS), вы также можете изучить прокси-сервер для разработки веб-пакетов. По ссылке Проксирование некоторых URL-адресов может быть полезно, если у вас есть отдельный сервер разработки API-интерфейса и вы хотите отправлять запросы API в том же домене. Таким образом вы можете удалить CORS (если у вас есть код для что)   -  person ljubadr    schedule 19.01.2019


Ответы (2)


Похоже, ваш сеанс не был постоянным.

Проверьте, не изменили ли вы какие-либо значения в config/session.php, которые могут создать проблемы.

Вы можете проверить значения конфигурации сеанса по умолчанию здесь

Из комментариев @Wonka решил свою проблему, изменив

'same_site' => 'strict'

to

'same_site' => null
person ljubadr    schedule 18.01.2019
comment
В Laravel 7 'same_site' => 'lax', является опцией по умолчанию, потому что мы установим это значение как нестрогое, поскольку это безопасное значение по умолчанию. (это работает для меня, используя Sanctum, тот же домен SPA Laravel + Vue) - person agm1984; 08.06.2020

Это выполнимо (и я сам сделал то же самое для некоторых приложений).

По умолчанию для маршрутов в routes/api.php недоступны сеансы, но вы можете добавить различные промежуточные программы для сеансов / файлов cookie в app/Http/Kernel.php (например, \Illuminate\Session\Middleware\StartSession::class) в маршруты API.

Вы можете, как предложил @ljubadr, также поместить маршруты API прямо в routes/web.php, хотя это, вероятно, означает, что вам нужно будет внести другие изменения (например, удалить защиту CSRF с веб-маршрутов).

person ceejayoz    schedule 16.01.2019
comment
Итак, я столкнулся с двумя проблемами, с которыми вы могли столкнуться в своих приложениях при использовании этого подхода. Я только что добавил обновление к вопросу; есть идеи, как это решить? - person Wonka; 16.01.2019
comment
Привет, извините, сеанс аутентификации по-прежнему не работает должным образом после интеграции вашего решения, как показано в моем обновлении. Вы можете взглянуть? Может быть для вас что-нибудь простое ... - person Wonka; 17.01.2019
comment
Почему CSRF может быть проблемой, поскольку запрос api, отправленный через правильно настроенные axios, отправит X-CSRF_TOKEN в заголовке? - person Hari Harker; 29.09.2020
comment
@HariHarker Правильный RESTful API не имеет состояния. Если вы хотите иметь API с отслеживанием состояния, это нормально; это, наверное, немного. - person ceejayoz; 29.09.2020