Получение 401 несанкционированного доступа для Laravel sanctum

Я использую Laravel Sanctum с Vuejs SPA. Оба находятся в одном домене верхнего уровня

Laravel backend : app.demo.localhost
Vue SPA : app-spa.demo.localhost

Вход и выход из системы (конечные точки) работают правильно при вызове из VueJS SPA с использованием axios и успешно установлен XSRF-TOKEN, но когда я вызываю другие конечные точки api, он дает мне 401 неавторизованный.

В аксиомах это устанавливается

axios.defaults.withCredentials = true;

У меня есть следующие конфигурации

В Laravel .env

SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost

В Routes/Api.php

Route::middleware('auth:sanctum')->get('api/user', function (Request $request) {
   return $request->user();
});

В cors.php

'paths' => ['api/*', 'sanctum/csrf-cookie', 'login', 'logout'],

'allowed_methods' => ['*'],

'allowed_origins' => ['*'],

'allowed_origins_patterns' => [],

'allowed_headers' => ['*'],

'exposed_headers' => [],

'max_age' => 0,

'supports_credentials' => true,

Может кто-нибудь мне помочь?

10 ответов

Если вы используете php artisan serve, добавьте номер порта в SANCTUM_STATEFUL_DOMAINS. Итак, если ваш номер порта 8000:

SESSION_DRIVER=cookie
SESSION_DOMAIN=.demo.localhost
SANCTUM_STATEFUL_DOMAINS=app-spa.demo.localhost:8000

Ваш SANCTUM_STATEFUL_DOMAINS должен соответствовать URL-адресу в вашем браузере. Номер порта не должен находиться в SESSION_DOMAIN.

Ниже приведены 8 шагов, которые я выполняю при настройке проверки святилища Laravel, если вы что-то пропустили.

Шаг 1 composer require laravel/sanctum

Шаг 2 php artisan vendor:publish --provider="Laravel\Sanctum\SanctumServiceProvider

Шаг 3 php artisan migrate (вы можете игнорировать это, если используете спа)

Шаг 4 раскомментируйте эту строку из app / http / kernel.php \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,

Шаг 5 В config / cors.php update 'supports_credentials' => true,

Шаг 6 В обновлении файла .env SESSION_DRIVER=cookie и добавить новую строку SESSION_DOMAIN=localhost(даже если вы используете какой-либо порт, например 8080, просто укажите localhost в session_domain)

Шаг 7 В config / sanctum.php добавьте свой клиентский домен вместе с портом (если он локальный) с сохранением состояния следующим образом, в моем случае для vue CLI это обычно localhost:8080 и для этого localhost:3000 , код выглядит следующим образом

          'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:8000,localhost:8080,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
        env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
    ))),

В основном, если ваше состояние (шаг 7) не настроено должным образом, вы получите 401 неавторизованный или он попытается перенаправить вас на домашнюю страницу вместе с ошибкой политики cors

Step8 Не забудьте await до sanctum/csrf-cookie обещание решено

          async login() {
      await axios.get("http://localhost:8000/sanctum/csrf-cookie");

      await axios.post("http://localhost:8000/login", {
        email: "kunal@gmail.com",
        password: "password",
      });

      let response = await axios.get("http://localhost:8000/api/user");
      console.log(response.data);
    },

Для тех, кто имеет дело с localhost:

      SESSION_DRIVER=cookie    
SESSION_DOMAIN=localhost    
SANCTUM_STATEFUL_DOMAINS=localhost:8080(port number you use)

Для меня мне просто нужно было разместить хост с номером порта:

SANCTUM_STATEFUL_DOMAINS=127.0.0.1:5173

и он начал работать. Может быть, это кому-то поможет.

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

Затем я использую routes/web.php вместо routes/api.php, поэтому я могу очень хорошо использовать промежуточное программное обеспечение sanctum.

Теперь проблема кажется очевидной: Axios withCredentials, возможно, нужно разместить правильно.

const http = axios.create({
    baseURL: API_URL,
    withCredentials: true
})

может не получится. Я добавляю{withCredentials: true} подобно

http.get('/api/whoami', {withCredentials: true})
  .then(res => {
                console.log(res.data)
            })

Тогда это работает.

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

Моя проблема заключалась в том, что я настроил домен в неправильном месте. Я думал, что это массив доменов, в config/sanctum.php, но не должен быть помещен в строку:

ХОРОШО:

          'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1,myownlocaldomain.test,myownlocaldomain.test:8080', <-------- OK
        env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
    ))),

ПЛОХО:

          'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
        '%s%s',
        'localhost,localhost:3000,127.0.0.1,127.0.0.1:8000,::1',
        env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : '',
        'myownlocaldomain.test', <----- BAD
        'myownlocaldomain.test:8080', <---- BAD
    ))),

Я надеюсь, что сэкономлю дни работы кому-то другому...

Привет, я нашел решение.

Мой SPA - это Vue v3, работающий на порту 3000. Также мой бэкэнд работает на 80 порту. (ларавель 8.1)

Сделайте Stateful Domains в config/sanctum.php вот так

       'stateful' => explode(',', env('SANCTUM_STATEFUL_DOMAINS', sprintf(
    '%s%s',
    'localhost:3000',
    env('APP_URL') ? ','.parse_url(env('APP_URL'), PHP_URL_HOST) : ''
))),

Добавление только одного и правильного домена у меня сработало волшебным образом. Я уже писал там весь возможный вариант портов, меня это взбесило и стоило пары дней и ночей.

Моя проблема была .... (не читать внимательно)

Если вашему SPA необходимо аутентифицироваться с помощью частных каналов / каналов присутствия, вы должны поместить вызов метода Broadcast ::routes в свой файл routes / api.php :

Laravel 10 с пакетом VueJs 3 и Sanctum. Я решил эту проблему, установивAPP_URL=[my domain name]в.envфайл, значение которого соответствует имени домена в веб-браузере.

Попробуйте это. Надеюсь, поможет.

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

Например

API Ларавел

      localhost:8000

Приложение Vuejs

      locahost:5781

Поэтому вам необходимо аутентифицировать его, отправляя заголовок авторизации при разработке на вашем локальном хосте. Примечание. Делайте это только в вашей локальной среде разработки. Поэтому поместите приведенный ниже код в if.

      axios.interceptors.request.use(
  config => {
    // Do something before request is sent
    
    if(process.env.dev) {
       // accessToken was set after a successful login
       const accessToken = localStorage.getItem('accessToken')
    
       if (accessToken) config.headers.Authorization = `Bearer ${accessToken}`
    }
    

    return config
  },
error => Promise.reject(error),
)
Другие вопросы по тегам