Задать вопрос
tol64
@tol64

Laragon/Nginx + Laravel + Nuxt: 419 — CSRF token mismatch?

Прошу помочь разобраться и решить задачу. Серия уроков, материал которых взял за основу: https://youtu.be/KFgi3IqavK4

ОС Windows 10

Путь к проекту:
C:\laragon\www\larastart-project

В этой директории две папки:
C:\laragon\www\larastart-project\backend
C:\laragon\www\larastart-project\frontend

В первую (backend) установлен фреймворк Laravel.
Во вторую (frontend) установлен фреймворк Nuxt.

Настройки Laragon/Nginx:

5ef5eb3419cb4459276935.png

Содержимое файла auto.larastart-project.test.conf:

server {
    listen 8080;
    listen 8443 ssl;
    server_name larastart-project.test *.larastart-project.test;
    root "C:/laragon/www/larastart-project/";
    
    index index.html index.htm index.php;
 
    location / {
		proxy_buffers 16 4k;
		proxy_buffer_size 2k;
		
		# npm run dev
		proxy_pass http://localhost:3000;
		
        # try_files $uri $uri/ /index.php$is_args$args;
		# autoindex on;
    }
	
    location /api {
		proxy_set_header Host $host;
		proxy_set_header X-Real-IP $remote_addr;
		
		# php artisan serve
		proxy_pass http://localhost:8000/api;
    }
    
    location ~ \.php$ {
        include snippets/fastcgi-php.conf;
        fastcgi_pass php_upstream;		
        #fastcgi_pass unix:/run/php/php7.0-fpm.sock;
    }

    # Enable SSL
    ssl_certificate "C:/laragon/etc/ssl/laragon.crt";
    ssl_certificate_key "C:/laragon/etc/ssl/laragon.key";
    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;
	
	
    charset utf-8;
	
    location = /favicon.ico { access_log off; log_not_found off; }
    location = /robots.txt  { access_log off; log_not_found off; }
    location ~ /\.ht {
        deny all;
    }
}


Настройки Laravel

Зависимости в composer.json. Для аутентификации используется пакет Sanctum: https://laravel.com/docs/7.x/sanctum#spa-authentication

"require": {
        "php": "^7.2.5",
        "fideloper/proxy": "^4.2",
        "fruitcake/laravel-cors": "^2.0",
        "guzzlehttp/guzzle": "^6.3",
        "intervention/image": "^2.5",
        "laravel/framework": "^7.0",
        "laravel/sanctum": "^2.4",
        "laravel/tinker": "^2.0",
        "spatie/laravel-medialibrary": "8.0.0"
    },
    "require-dev": {
        "barryvdh/laravel-ide-helper": "^2.7",
        "facade/ignition": "^2.0",
        "fzaninotto/faker": "^1.9.1",
        "laravel/ui": "^2.0",
        "mockery/mockery": "^1.3.1",
        "nunomaduro/collision": "^4.1",
        "phpunit/phpunit": "^8.5"
    },


Файл .env

APP_URL=http://localhost
CORS_ALLOWED_ORIGIN=http://localhost:3000
SANCTUM_STATEFUL_DOMAINS=http://localhost:8000
SESSION_DRIVER=file
SESSION_DOMAIN=localhost


Файл config\cors.php

return [
    'paths' => [
        'api/*',
        'login',
        'logout',
        'user',
        'sanctum/csrf-cookie',
    ],
    'allowed_methods' => ['*'],
    'allowed_origins' => ['*'],
    'allowed_origins_patterns' => [],
    'allowed_headers' => ['*'],
    'exposed_headers' => [],
    'max_age' => 0,
    'supports_credentials' => true,
];


Файл app\Http\Kernel.php

protected $middlewareGroups = [
...
        'api' => [
            EnsureFrontendRequestsAreStateful::class,
            'throttle:60,1',
            \Illuminate\Routing\Middleware\SubstituteBindings::class,
        ],
    ];


Настройки Nuxt

Зависимости в package.json

"dependencies": {
        "@nuxtjs/auth": "^4.9.1",
        "@nuxtjs/axios": "^5.3.6",
        "@nuxtjs/dotenv": "^1.4.1",
        "@nuxtjs/proxy": "^2.0.0",
        "bootstrap": "^4.5.0",
        "bootstrap-vue": "^2.15.0",
        "cookie-universal-nuxt": "^2.1.4",
        "iview": "^3.1.5",
        "jquery": "^3.5.1",
        "moment": "^2.27.0",
        "nuxt": "^2.0.0",
        "popper.js": "^1.16.1",
        "prismjs": "^1.20.0"
    },
    "devDependencies": {
        "node-sass": "^4.14.1",
        "nuxt-purgecss": "^1.0.0",
        "sass-loader": "^8.0.2"
    }


Файл .env

API_URL=http://localhost:8000/api
API_DOMAIN=http://localhost:8000


Файл nuxt.config.js. Показаны настройки относящиеся к аутентификации.

...
    modules: [
        '@nuxtjs/axios',
        '@nuxtjs/auth',
        '@nuxtjs/proxy',
        '@nuxtjs/dotenv',
        'bootstrap-vue/nuxt',
        [
            'cookie-universal-nuxt', {
                alias: 'cookie'
            }
        ],
    ],
    auth: {
        strategies: {
            local: {
                endpoints: {
                    login: {
                        url: process.env.API_DOMAIN + '/login',
                        method: 'post'
                    },
                    logout: {
                        url: process.env.API_DOMAIN + '/logout',
                        method: 'post'
                    },
                    user: {
                        url: process.env.API_DOMAIN + '/user',
                        method: 'get',
                        propertyName: false
                    }
                },
                tokenRequired: false,
                tokenType: false
            }
        }
    },
    axios: {
        baseURL: process.env.API_DOMAIN,
        credentials: true
    },
...


Проверяем запрос токена в программе Postman: https://www.postman.com/

Видно, что данные отдаются.

5ef5ed1e63a95817778704.png

Далее делаем страницу с формой для теста: pages\auth\signin.vue

Код метода:

methods: {
        async login() {
            try {
                await this.$axios.$get('http://localhost:8000/sanctum/csrf-cookie');
                await this.$auth.loginWith('local', {
                    email: this.form.email,
                    password: this.form.password,
                });
                this.$router.replace('/');
            } 
            catch (e) {
                this.errors = 'Could not sign you with these credentials.';
                console.log(e);
            }
        }
    }


Результат:

5ef5ed5f42e84809764466.png

Подробнее:

5ef5ed848bf00901428271.png

5ef5eddeaf4dd818492828.png

5ef5ee01303d2912441857.png

В списке Cookies на вкладке Application нет XSRF-TOKEN. Вроде бы здесь он тоже должен быть при отправке данных формы.

5ef5ee3304018391032231.png
  • Вопрос задан
  • 1115 просмотров
Подписаться 1 Простой 2 комментария
Пригласить эксперта
Ответы на вопрос 1
@kami16ru
У вас запрос на csrf куку возвращает ок.
1. Удалите куки из браузера
2. В ларавеле выполните команды:
  • php artisan config:clear
  • php artisan cache:clear
  • php artisan config:cache

Если вы вносили изменения в кеш, они не всегда могут закешироваться из за проблем с правами (сам так и не понял почему, грешу на IDE, который пишет в файлах под рутом). Лучше всегда чистить кэш, после того как вносили изменения в папке config.

Если при выполнении этих операций у вас ошибка с правами, не в коем случае не решайте ее выдачей прав 777 на данную папку. Просто удалите вручную кеш файл, у которого права root root. Проверить права в текущей директории можно командой ls -la

3. axios: {
baseURL: process.env.API_DOMAIN,
credentials: true
},

По моему тут нужно withCredentials: true

4. async login() {
try {
await this.$axios.$get('localhost:8000/sanctum/csrf-cookie');
await this.$auth.loginWith('local', {
email: this.form.email,
password: this.form.password,
});
this.$router.replace('/');
}
catch (e) {
this.errors = 'Could not sign you with these credentials.';
console.log(e);
}
}

Я бы засунул второй запрос в .then

await this.$axios.$get('localhost:8000/sanctum/csrf-cookie')
.then(() => {
this.$axios.$post('yourPostRoute', yourPostData)
});
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы