Httponly cookie не устанавливается / хранится (Laravel / Vue) - PullRequest
0 голосов
/ 05 ноября 2019

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

Создаю простую систему аутентификации сVue внешний интерфейс (созданный с использованием vue-cli) и Laravel 5.8 (api) для внутреннего интерфейса;протестировать идею использования httponly cookie для аутентификации и защиты доступа к определенным маршрутам после прочтения этой статьи. Я использую tymondesigns / jwt-auth для аутентификации вместо паспорт laravel , используемый в статье, и также использую пакет barryvdh / laravel-cors для добавления CORSПоддержка заголовков (Cross-Origin Resource Sharing).

BACKEND

Вот мой код в routes/api.php

Route::group(['prefix' => 'auth', 'namespace' => 'Auth'], function () {
    Route::post('login', 'AuthController@login');

    Route::group(['middleware' => ['auth.api'],], function () {
        Route::get('me', 'AuthController@me');
        Route::post('logout', 'AuthController@logout');
    });
});

И код для промежуточного программного обеспечения, которое используетсявыглядит следующим образом в app/Http/Kernel.php

'auth.api' => [
    \App\Http\Middleware\AddAuthTokenHeader::class,
    'throttle:60,1',
    'bindings',
    'auth:api',
    \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
],

А вот мой код в app/Http/Controllers/Auth/AuthController.php

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Requests\Auth\LoginRequest;

use App\Http\Controllers\Controller;

class AuthController extends Controller
{
    /**
     * Authenticate user via given credentials.
     *
     * @param \App\Http\Requests\Auth\LoginRequest $request
     *
     * @return \Illuminate\Http\JsonResponse
     */
    public function login(LoginRequest $request)
    {
        $credentials = $request->all(['email', 'password']);

        if (!$token = auth()->attempt($credentials)) {
            return response()->json(['error' => 'Invalid credentials'], 401);
        }

        $cookie = $this->getCookie($token);

        return response()->json([
            'token' => $token,
            'user' => auth()->user(),
        ])->withCookie($cookie);
    }

    /**
     * Set cookie details and return cookie
     *
     * @param string $token JWT
     *
     * @return \Illuminate\Cookie\CookieJar|\Symfony\Component\HttpFoundation\Cookie
     */
    private function getCookie($token)
    {
        return cookie(
            env('AUTH_COOKIE_NAME'),
            $token,
            auth()->factory()->getTTL(),
            null,
            null,
            env('APP_DEBUG') ? false : true,
            true,
            false,
            'Strict'
        );
    }

    public function logout()
    {
        // ...
    }

    public function me()
    {
        // ...
    }
}

И код метода handle в классе промежуточного программного обеспечения (app/Http/Middleware/AddAuthTokenHeader.php) используемое в пользовательском промежуточном программном обеспечении auth.api равно

public function handle($request, Closure $next)
{
    $cookie_name = env('AUTH_COOKIE_NAME');

    if (!$request->bearerToken()) {
        if ($request->hasCookie($cookie_name)) {
            $token = $request->cookie($cookie_name);

            $request->headers->add([
                'Authorization' => 'Bearer ' . $token
            ]);
        }
    }

    return $next($request);
}

Как вы можете видеть в моем AuthController, как только запрос на вход успешно выполнен, ответ json отправляется вместе с файлом cookie только для http.

ПРИМЕЧАНИЕ : я использую php artisan serve для запуска моего бэкэнда

FRONT-END

После запуска npm run serve в моем сгенерированном проекте vue-cli яперейдите на маршрут login, который отображает компонент Login, представленный @/views/Login.vue.

Вот мой код для Login.vue

<template>
    <div>
        <form @submit.prevent="submit" autocomplete="off">
            <p>
                <label for="email">Email: </label>
                <input
                    type="email"
                    name="email"
                    id="email"
                    v-model.lazy="form.email"
                    required
                    autofocus
                />
            </p>
            <p>
                <label for="password">Password: </label>
                <input
                    type="password"
                    name="password"
                    id="password"
                    v-model.lazy="form.password"
                    required
                />
            </p>
            <button type="submit">Login</button>
        </form>
    </div>
</template>

<script>
import axios from 'axios';

export default {
    name: 'login',
    data() {
        return {
            form: {
                email: '',
                password: '',
            },
        };
    },

    methods: {
        async submit() {
            const url = 'http://localhost:8000/api/auth/login';
            const response = await axios.post(url, this.form, {
                headers: {
                    Accept: 'application/json',
                    'Content-Type': 'application/json',
                },
            });

            console.log(response);
            // this.$router.replace({ name: 'home' });
        },
    },
};
</script>

При наличии действительных учетных данных на маршруте (http:localhost:8080/login), cookie будет возвращен, как видно из заголовков ответов ниже

enter image description here

, но по какой-то причине он не устанавливается в хранилище cookie-файлов браузера, как показано ниже

enter image description here

ПРИМЕЧАНИЕ : файл cookie, показанный выше, от меня проверяет, все ли работает нормально после запуска php artisan serve и открытия http:localhost:8000 в браузере.

Вопроспочему cookie не хранится в хранилище cookie браузера?

Следует отметить, что когда я вызываю те же API-интерфейсы бэкэнда, используя POSTMAN, все работает нормально (при установленном cookieпри входе в систему и очищается при выходе).

Спасибо.

1 Ответ

0 голосов
/ 06 ноября 2019

Вся благодарность @skirtle за помощь в решении этой проблемы;Ваша помощь была неоценима.

Вот шаги, которые я предпринял, чтобы заставить ее работать.

BACKEND

Я запускаю команду php artisan vendor:publish --provider="Barryvdh\Cors\ServiceProvider", которая создает файл cors.php вкаталог config.

Затем я изменил эту строку 'supportsCredentials' => false, в config/cors.php на 'supportsCredentials' => true, и оставил все остальное таким же, после чего я запускаю следующие команды, просто чтобы убедиться, что новые изменения были

php artisan config:clear
php artisan cache:clear

php artisan serve

FRONTEND

Все, что у меня было, - это изменить мой метод submit в Login.vue на этот

async submit() {
    const url = 'http://localhost:8000/api/auth/login';
    const response = await axios.post(url, this.form, {
        withCredentials: true,
        headers: {
            Accept: 'application/json',
            'Content-Type': 'application/json',
        },
    });

    console.log(response.data);
    // this.$router.replace({ name: 'home' });
},

И теперь файл cookieустанавливается так, как показано ниже

enter image description here

Еще раз, большое спасибо и благодарность @skirtle за советы.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...