Я уже несколько часов бьюсь над этим, чтобы решить эту проблему, и пока просто не могу обойти ее.
Создаю простую систему аутентификации с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 будет возвращен, как видно из заголовков ответов ниже
, но по какой-то причине он не устанавливается в хранилище cookie-файлов браузера, как показано ниже
ПРИМЕЧАНИЕ : файл cookie, показанный выше, от меня проверяет, все ли работает нормально после запуска php artisan serve
и открытия http:localhost:8000
в браузере.
Вопроспочему cookie не хранится в хранилище cookie браузера?
Следует отметить, что когда я вызываю те же API-интерфейсы бэкэнда, используя POSTMAN
, все работает нормально (при установленном cookieпри входе в систему и очищается при выходе).
Спасибо.